/**
 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "plugins/ecmascript/runtime/builtins.h"

#include "ecma_vm.h"
#include "init_icu.h"
#include "plugins/ecmascript/runtime/base/error_type.h"
#include "plugins/ecmascript/runtime/base/number_helper.h"
#include "plugins/ecmascript/runtime/containers/containers_private.h"
#include "plugins/ecmascript/runtime/ecma_runtime_call_info.h"
#include "plugins/ecmascript/runtime/js_array.h"
#include "plugins/ecmascript/runtime/js_arraybuffer.h"
#include "plugins/ecmascript/runtime/js_arraylist.h"
#include "plugins/ecmascript/runtime/js_array_iterator.h"
#include "plugins/ecmascript/runtime/js_async_from_sync_iterator_object.h"
#include "plugins/ecmascript/runtime/js_async_function.h"
#include "plugins/ecmascript/runtime/js_async_generator_object.h"
#include "plugins/ecmascript/runtime/js_collator.h"
#include "plugins/ecmascript/runtime/js_dataview.h"
#include "plugins/ecmascript/runtime/js_date_time_format.h"
#include "plugins/ecmascript/runtime/js_for_in_iterator.h"
#include "plugins/ecmascript/runtime/js_function.h"
#include "plugins/ecmascript/runtime/js_handle.h"
#include "plugins/ecmascript/runtime/js_hclass.h"
#include "plugins/ecmascript/runtime/js_locale.h"
#include "plugins/ecmascript/runtime/js_map.h"
#include "plugins/ecmascript/runtime/js_map_iterator.h"
#include "plugins/ecmascript/runtime/js_number_format.h"
#include "plugins/ecmascript/runtime/js_plural_rules.h"
#include "plugins/ecmascript/runtime/js_primitive_ref.h"
#include "plugins/ecmascript/runtime/js_promise.h"
#include "plugins/ecmascript/runtime/js_regexp.h"
#include "plugins/ecmascript/runtime/js_regexp_iterator.h"
#include "plugins/ecmascript/runtime/js_relative_time_format.h"
#include "plugins/ecmascript/runtime/js_runtime_options.h"
#include "plugins/ecmascript/runtime/js_set.h"
#include "plugins/ecmascript/runtime/js_set_iterator.h"
#include "plugins/ecmascript/runtime/js_string_iterator.h"
#include "plugins/ecmascript/runtime/js_tagged_value.h"
#include "plugins/ecmascript/runtime/js_typed_array.h"
#include "plugins/ecmascript/runtime/js_weak_container.h"
#include "plugins/ecmascript/runtime/js_finalization_registry.h"
#include "plugins/ecmascript/runtime/mem/mem.h"
#include "plugins/ecmascript/runtime/object_factory.h"

namespace ark::ecmascript::builtins {

using ErrorType = base::ErrorType;
using ContainersPrivate = containers::ContainersPrivate;

void Builtins::Initialize(const JSHandle<GlobalEnv> &env, JSThread *thread)
{
    thread_ = thread;
    vm_ = thread->GetEcmaVM();
    factory_ = vm_->GetFactory();
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());

    // Object.prototype[dynclass]
    JSHandle<JSHClass> objPrototypeDynclass = factory_->CreateDynClass<JSObject>(JSType::JS_OBJECT, nullHandle);

    // Object.prototype
    JSHandle<JSObject> objFuncPrototype = factory_->NewJSObject(objPrototypeDynclass);
    JSHandle<JSTaggedValue> objFuncPrototypeVal(objFuncPrototype);

    // Object.prototype_or_dynclass
    JSHandle<JSHClass> objFuncDynclass = factory_->CreateDynClass<JSObject>(JSType::JS_OBJECT, objFuncPrototypeVal);

    // GLobalObject.prototype_or_dynclass
    JSHandle<JSHClass> globalObjFuncDynclass = factory_->CreateDynClass<JSObject>(JSType::JS_GLOBAL_OBJECT, 0);
    globalObjFuncDynclass->SetPrototype(thread_, objFuncPrototypeVal.GetTaggedValue());
    globalObjFuncDynclass->SetIsDictionaryMode(true);
    // Function.prototype_or_dynclass
    JSHandle<JSHClass> emptyFuncDynclass(
        factory_->CreateDynClass<JSFunction>(JSType::JS_FUNCTION, objFuncPrototypeVal, HClass::IS_CALLABLE));
    emptyFuncDynclass->SetExtensible(true);

    // PrimitiveRef.prototype_or_dynclass
    JSHandle<JSHClass> primRefObjDynclass =
        factory_->CreateDynClass<JSPrimitiveRef>(JSType::JS_PRIMITIVE_REF, objFuncPrototypeVal);

    // init global object
    JSHandle<JSObject> globalObject = factory_->NewNonMovableJSObject(globalObjFuncDynclass);
    JSHandle<JSHClass> newGlobalDynclass = JSHClass::Clone(thread_, globalObjFuncDynclass);
    globalObject->SetClass(newGlobalDynclass);
    env->SetJSGlobalObject(thread_, globalObject);

    // initialize Function, forbidden change order
    InitializeFunction(env, emptyFuncDynclass);

    JSHandle<JSObject> objFuncInstancePrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> objFuncInstancePrototypeValue(objFuncInstancePrototype);
    JSHandle<JSHClass> asyncFuncClass = factory_->CreateFunctionClass<JSAsyncFunction>(
        FunctionKind::ASYNC_FUNCTION, JSType::JS_ASYNC_FUNCTION, objFuncInstancePrototypeValue);
    asyncFuncClass->SetExtensible(true);
    env->SetAsyncFunctionClass(thread_, asyncFuncClass);

    JSHandle<JSHClass> asyncAwaitStatusFuncClass = factory_->CreateFunctionClass<JSAsyncAwaitStatusFunction>(
        FunctionKind::NORMAL_FUNCTION, JSType::JS_ASYNC_AWAIT_STATUS_FUNCTION, env->GetFunctionPrototype());
    env->SetAsyncAwaitStatusFunctionClass(thread_, asyncAwaitStatusFuncClass);

    JSHandle<JSHClass> asyncGeneratorResolveNextFuncClass =
        factory_->CreateDynClass<JSAsyncGeneratorResolveNextFunction>(JSType::JS_ASYNC_GENERATOR_RESOLVE_NEXT_FUNCTION,
                                                                      env->GetFunctionPrototype(), HClass::IS_CALLABLE);
    asyncGeneratorResolveNextFuncClass->SetExtensible(true);
    env->SetAsyncGeneratorResolveNextFunctionClass(thread_, asyncGeneratorResolveNextFuncClass);

    JSHandle<JSHClass> asyncFromSyncIteratorValueUnwrapFuncClass =
        factory_->CreateDynClass<JSAsyncFromSyncIteratorValueUnwrapFunction>(
            JSType::JS_ASYNC_FROM_SYNC_ITERATOR_VALUE_UNWRAP_FUNCTION, env->GetFunctionPrototype(),
            HClass::IS_CALLABLE);
    asyncFromSyncIteratorValueUnwrapFuncClass->SetExtensible(true);
    env->SetAsyncFromSyncIteratorValueUnwrapFunctionClass(thread_, asyncFromSyncIteratorValueUnwrapFuncClass);

    JSHandle<JSHClass> promiseReactionFuncClass = factory_->CreateDynClass<JSPromiseReactionsFunction>(
        JSType::JS_PROMISE_REACTIONS_FUNCTION, env->GetFunctionPrototype(), HClass::IS_CALLABLE);
    promiseReactionFuncClass->SetExtensible(true);
    env->SetPromiseReactionFunctionClass(thread_, promiseReactionFuncClass);

    JSHandle<JSHClass> promiseExecutorFuncClass = factory_->CreateDynClass<JSPromiseExecutorFunction>(
        JSType::JS_PROMISE_EXECUTOR_FUNCTION, env->GetFunctionPrototype(), HClass::IS_CALLABLE);
    promiseExecutorFuncClass->SetExtensible(true);
    env->SetPromiseExecutorFunctionClass(thread_, promiseExecutorFuncClass);

    JSHandle<JSHClass> promiseAllResolveElementFunctionClass =
        factory_->CreateDynClass<JSPromiseAllResolveElementFunction>(JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION,
                                                                     env->GetFunctionPrototype(), HClass::IS_CALLABLE);
    promiseAllResolveElementFunctionClass->SetExtensible(true);
    env->SetPromiseAllResolveElementFunctionClass(thread_, promiseAllResolveElementFunctionClass);

    JSHandle<JSHClass> proxyRevocFuncClass = factory_->CreateDynClass<JSProxyRevocFunction>(
        JSType::JS_PROXY_REVOC_FUNCTION, env->GetFunctionPrototype(), HClass::IS_CALLABLE);
    proxyRevocFuncClass->SetExtensible(true);
    env->SetProxyRevocFunctionClass(thread_, proxyRevocFuncClass);

    // Object = new Function()
    JSHandle<JSObject> objectFunction(
        NewBuiltinConstructor(env, objFuncPrototype, object::ObjectConstructor, "Object", FunctionLength::ONE));
    objectFunction.GetObject<JSFunction>()->SetFunctionPrototype(thread_, objFuncDynclass.GetTaggedValue());
    // initialize object method.
    env->SetObjectFunction(thread_, objectFunction);
    env->SetObjectFunctionPrototype(thread_, objFuncPrototype);

    JSHandle<JSHClass> functionClass = factory_->CreateFunctionClass<JSFunction>(
        FunctionKind::BASE_CONSTRUCTOR, JSType::JS_FUNCTION, env->GetFunctionPrototype());
    env->SetFunctionClassWithProto(thread_, functionClass);
    functionClass = factory_->CreateFunctionClass<JSFunction>(FunctionKind::NORMAL_FUNCTION, JSType::JS_FUNCTION,
                                                              env->GetFunctionPrototype());
    env->SetFunctionClassWithoutProto(thread_, functionClass);
    functionClass = factory_->CreateFunctionClass<JSFunction>(FunctionKind::CLASS_CONSTRUCTOR, JSType::JS_FUNCTION,
                                                              env->GetFunctionPrototype());
    env->SetFunctionClassWithoutName(thread_, functionClass);

    if (env == vm_->GetGlobalEnv()) {
        InitializeAllTypeError(env, objFuncDynclass);
        InitializeSymbol(env, primRefObjDynclass);
    } else {
        // error and symbol need to be shared when initialize realm
        InitializeAllTypeErrorWithRealm(env);
        InitializeSymbolWithRealm(env, primRefObjDynclass);
    }

    InitializeNumber(env, primRefObjDynclass);
    InitializeBigInt(env, objFuncDynclass);
    InitializeDate(env, objFuncDynclass);
    InitializeObject(env, objFuncPrototype, objectFunction);
    InitializeBoolean(env, primRefObjDynclass);

    InitializeRegExp(env);
    InitializeSet(env, objFuncDynclass);
    InitializeMap(env, objFuncDynclass);
    InitializeWeakRef(env, objFuncDynclass);
    InitializeWeakMap(env, objFuncDynclass);
    InitializeWeakSet(env, objFuncDynclass);
    InitializeArray(env, objFuncPrototypeVal);
    InitializeTypedArray(env, objFuncDynclass);
    InitializeString(env, primRefObjDynclass);
    InitializeArrayBuffer(env, objFuncDynclass);
    InitializeDataView(env, objFuncDynclass);

    JSHandle<JSHClass> argumentsDynclass = factory_->CreateJSArguments();
    env->SetArgumentsClass(thread_, argumentsDynclass);
    SetArgumentsSharedAccessor(env);

    InitializeGlobalObject(env, globalObject);
    InitializeMath(env, objFuncPrototypeVal);
    InitializeJson(env, objFuncPrototypeVal);
    InitializeIterator(env, objFuncDynclass);
    InitializeAsyncIterator(env, objFuncDynclass);
    InitializeProxy(env);
    InitializeReflect(env, objFuncPrototypeVal);
    InitializeAsyncFunction(env, objFuncDynclass);
    InitializeGenerator(env, objFuncDynclass);
    InitializeGeneratorFunction(env, objFuncDynclass);
    InitializeAsyncGenerator(env, objFuncDynclass);
    InitializeAsyncGeneratorFunction(env, objFuncDynclass);
    InitializeAsyncFromSyncIteratorPrototypeObject(env, objFuncDynclass);
    InitializePromise(env, objFuncDynclass);
    InitializePromiseJob(env);
    InitializeFinalizationRegistry(env, objFuncDynclass);

    std::string icuPath = vm_->GetJSOptions().GetIcuDataPath();
    if (icuPath == "default") {
        SetIcuDirectory();
    } else {
        u_setDataDirectory(icuPath.c_str());
    }
    InitializeIntl(env, objFuncPrototypeVal);
    InitializeLocale(env);
    InitializeDateTimeFormat(env);
    InitializeNumberFormat(env);
    InitializeRelativeTimeFormat(env);
    InitializeCollator(env);
    InitializePluralRules(env);

    JSHandle<JSHClass> generatorFuncClass = factory_->CreateFunctionClass<JSGeneratorFunction>(
        FunctionKind::GENERATOR_FUNCTION, JSType::JS_GENERATOR_FUNCTION, env->GetGeneratorFunctionPrototype());
    env->SetGeneratorFunctionClass(thread_, generatorFuncClass);

    JSHandle<JSHClass> asyncGeneratorFuncClass = factory_->CreateFunctionClass<JSAsyncGeneratorFunction>(
        FunctionKind::ASYNC_GENERATOR_FUNCTION, JSType::JS_ASYNC_GENERATOR_FUNCTION,
        env->GetAsyncGeneratorFunctionPrototype());
    env->SetAsyncGeneratorFunctionClass(thread_, asyncGeneratorFuncClass);

    env->SetObjectFunctionPrototypeClass(thread_, JSTaggedValue(objFuncPrototype->GetClass()));
    thread_->ResetGuardians();

#ifdef FUZZING_FUZZILLI_BUILTIN
    InitializeFuzzilli(env, objFuncDynclass);
#endif
}

void Builtins::InitializeGlobalObject(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &globalObject)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);

    InitializeGcMarker(env);

    // NOTE(ivagin): Remove ArkTools?
    if (vm_->GetJSOptions().IsEnableArkTools()) {
        JSHandle<JSTaggedValue> arkTools(InitializeArkTools(env));
        SetConstantObject(globalObject, "ArkTools", arkTools);
    }

#ifndef PANDA_PRODUCT_BUILD
    JSHandle<JSTaggedValue> runtimeTesting(InitializeRuntimeTesting(env));
    SetConstantObject(globalObject, "RuntimeTesting", runtimeTesting);
#endif  // PANDA_PRODUCT_BUILD

#if ECMASCRIPT_ENABLE_ARK_CONTAINER
    // Set ArkPrivate
    JSHandle<JSTaggedValue> ark_private(InitializeArkPrivate(env));
    SetConstantObject(global_object, "ArkPrivate", ark_private);
#endif

    // Global object property
    SetGlobalThis(globalObject, "globalThis", JSHandle<JSTaggedValue>::Cast(globalObject));
    SetConstant(globalObject, "Infinity", JSTaggedValue(base::POSITIVE_INFINITY));
    SetConstant(globalObject, "NaN", JSTaggedValue(base::NAN_VALUE));
    SetConstant(globalObject, "undefined", JSTaggedValue::Undefined());

    SetFunctionsGenGlobal(env, globalObject);
}

void Builtins::InitializeFunction(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &emptyFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Initialize Function.prototype
    JSMethod *invokeSelf =
        vm_->GetMethodForNativeFunction(reinterpret_cast<void *>(builtins::function::FunctionPrototypeInvokeSelf));
    JSHandle<JSFunction> funcFuncPrototype = factory_->NewJSFunctionByDynClass(invokeSelf, emptyFuncDynclass);
    // ecma 19.2.3 The value of the name property of the Function prototype object is the empty String.
    JSHandle<JSTaggedValue> emptyString(thread_->GlobalConstants()->GetHandledEmptyString());
    JSHandle<JSTaggedValue> undefinedString(thread_, JSTaggedValue::Undefined());
    JSFunction::SetFunctionName(thread_, JSHandle<JSFunctionBase>(funcFuncPrototype), emptyString, undefinedString);
    // ecma 19.2.3 The value of the length property of the Function prototype object is 0.
    JSFunction::SetFunctionLength(thread_, funcFuncPrototype, JSTaggedValue(FunctionLength::ZERO));

    JSHandle<JSTaggedValue> funcFuncPrototypeValue(funcFuncPrototype);
    // Function.prototype_or_dynclass
    JSHandle<JSHClass> funcFuncIntanceDynclass = factory_->CreateDynClass<JSFunction>(
        JSType::JS_FUNCTION, funcFuncPrototypeValue, HClass::IS_CALLABLE | HClass::IS_BUILTINS_CTOR);
    funcFuncIntanceDynclass->SetConstructor(true);

    // Function = new Function() (forbidden use NewBuiltinConstructor)
    JSMethod *ctor = vm_->GetMethodForNativeFunction(reinterpret_cast<void *>(builtins::function::FunctionConstructor));
    JSHandle<JSFunction> funcFunc =
        factory_->NewJSFunctionByDynClass(ctor, funcFuncIntanceDynclass, FunctionKind::BUILTIN_CONSTRUCTOR);

    auto funcFuncPrototypeObj = JSHandle<JSObject>(funcFuncPrototype);
    InitializeCtor(env, funcFuncPrototypeObj, funcFunc, "Function", FunctionLength::ONE);

    funcFunc->SetFunctionPrototype(thread_, funcFuncIntanceDynclass.GetTaggedValue());
    env->SetFunctionFunction(thread_, funcFunc);
    env->SetFunctionPrototype(thread_, funcFuncPrototype);

    JSHandle<JSHClass> normalFuncClass =
        factory_->CreateDynClass<JSFunction>(JSType::JS_FUNCTION, env->GetFunctionPrototype(), HClass::IS_CALLABLE);
    env->SetNormalFunctionClass(thread_, normalFuncClass);

    JSHandle<JSHClass> jSIntlBoundFunctionClass = factory_->CreateFunctionClass<JSIntlBoundFunction>(
        FunctionKind::NORMAL_FUNCTION, JSType::JS_INTL_BOUND_FUNCTION, env->GetFunctionPrototype());
    env->SetJSIntlBoundFunctionClass(thread_, jSIntlBoundFunctionClass);

    JSHandle<JSHClass> constructorFunctionClass = factory_->CreateDynClass<JSFunction>(
        JSType::JS_FUNCTION, env->GetFunctionPrototype(), HClass::IS_CALLABLE | HClass::IS_BUILTINS_CTOR);
    constructorFunctionClass->SetConstructor(true);
    env->SetConstructorFunctionClass(thread_, constructorFunctionClass);

    StrictModeForbiddenAccessCallerArguments(env, funcFuncPrototypeObj);

    SetFunctionsGenFunctionProto(env, funcFuncPrototypeObj);
}

void Builtins::InitializeObject(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &objFuncPrototype,
                                const JSHandle<JSObject> &objFunc)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    SetFunctionsGenObject(env, objFunc);

    SetFunctionsGenObjectProto(env, objFuncPrototype);
}

void Builtins::InitializeSymbol(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    // Symbol.prototype
    JSHandle<JSObject> symbolFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> symbolFuncPrototypeValue(symbolFuncPrototype);

    // Symbol.prototype_or_dynclass
    JSHandle<JSHClass> symbolFuncInstanceDynclass =
        factory_->CreateDynClass<JSPrimitiveRef>(JSType::JS_PRIMITIVE_REF, symbolFuncPrototypeValue);

    // Symbol = new Function()
    JSHandle<JSObject> symbolFunction(NewBuiltinConstructor(
        env, symbolFuncPrototype, builtins::symbol::SymbolConstructor, "Symbol", FunctionLength::ZERO));
    JSHandle<JSFunction>(symbolFunction)->SetFunctionPrototype(thread_, symbolFuncInstanceDynclass.GetTaggedValue());

    // "constructor" property on the prototype
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    PropertyDescriptor descriptor(thread_, JSHandle<JSTaggedValue>::Cast(symbolFunction), true, false, true);
    JSObject::DefineOwnProperty(thread_, symbolFuncPrototype, constructorKey, descriptor);

    // Symbol attribute
    JSHandle<JSTaggedValue> hasInstanceSymbol(factory_->NewWellKnownSymbolWithChar("Symbol.hasInstance"));
    SetNoneAttributeProperty(symbolFunction, "hasInstance", hasInstanceSymbol);
    JSHandle<JSTaggedValue> isConcatSpreadableSymbol(factory_->NewWellKnownSymbolWithChar("Symbol.isConcatSpreadable"));
    SetNoneAttributeProperty(symbolFunction, "isConcatSpreadable", isConcatSpreadableSymbol);
    JSHandle<JSTaggedValue> toStringTagSymbol(factory_->NewWellKnownSymbolWithChar("Symbol.toStringTag"));
    SetNoneAttributeProperty(symbolFunction, "toStringTag", toStringTagSymbol);
    JSHandle<JSTaggedValue> iteratorSymbol(factory_->NewPublicSymbolWithChar("Symbol.iterator"));
    SetNoneAttributeProperty(symbolFunction, "iterator", iteratorSymbol);
    JSHandle<JSTaggedValue> asyncIteratorSymbol(factory_->NewPublicSymbolWithChar("Symbol.asyncIterator"));
    SetNoneAttributeProperty(symbolFunction, "asyncIterator", asyncIteratorSymbol);
    JSHandle<JSTaggedValue> matchSymbol(factory_->NewPublicSymbolWithChar("Symbol.match"));
    SetNoneAttributeProperty(symbolFunction, "match", matchSymbol);
    JSHandle<JSTaggedValue> matchAllSymbol(factory_->NewPublicSymbolWithChar("Symbol.matchAll"));
    SetNoneAttributeProperty(symbolFunction, "matchAll", matchAllSymbol);
    JSHandle<JSTaggedValue> replaceSymbol(factory_->NewPublicSymbolWithChar("Symbol.replace"));
    SetNoneAttributeProperty(symbolFunction, "replace", replaceSymbol);
    JSHandle<JSTaggedValue> searchSymbol(factory_->NewPublicSymbolWithChar("Symbol.search"));
    SetNoneAttributeProperty(symbolFunction, "search", searchSymbol);
    JSHandle<JSTaggedValue> speciesSymbol(factory_->NewPublicSymbolWithChar("Symbol.species"));
    SetNoneAttributeProperty(symbolFunction, "species", speciesSymbol);
    JSHandle<JSTaggedValue> splitSymbol(factory_->NewPublicSymbolWithChar("Symbol.split"));
    SetNoneAttributeProperty(symbolFunction, "split", splitSymbol);
    JSHandle<JSTaggedValue> toPrimitiveSymbol(factory_->NewPublicSymbolWithChar("Symbol.toPrimitive"));
    SetNoneAttributeProperty(symbolFunction, "toPrimitive", toPrimitiveSymbol);
    JSHandle<JSTaggedValue> unscopablesSymbol(factory_->NewPublicSymbolWithChar("Symbol.unscopables"));
    SetNoneAttributeProperty(symbolFunction, "unscopables", unscopablesSymbol);

    env->SetSymbolFunction(thread_, symbolFunction);
    env->SetHasInstanceSymbol(thread_, hasInstanceSymbol);
    env->SetIsConcatSpreadableSymbol(thread_, isConcatSpreadableSymbol);
    env->SetToStringTagSymbol(thread_, toStringTagSymbol);
    env->SetIteratorSymbol(thread_, iteratorSymbol);
    env->SetAsyncIteratorSymbol(thread_, asyncIteratorSymbol);
    env->SetMatchSymbol(thread_, matchSymbol);
    env->SetMatchAllSymbol(thread_, matchAllSymbol);
    env->SetReplaceSymbol(thread_, replaceSymbol);
    env->SetSearchSymbol(thread_, searchSymbol);
    env->SetSpeciesSymbol(thread_, speciesSymbol);
    env->SetSplitSymbol(thread_, splitSymbol);
    env->SetToPrimitiveSymbol(thread_, toPrimitiveSymbol);
    env->SetUnscopablesSymbol(thread_, unscopablesSymbol);

    // Setup %SymbolPrototype%
    SetStringTagSymbol(env, symbolFuncPrototype, "Symbol");

    JSHandle<JSTaggedValue> holeySymbol(factory_->NewPrivateNameSymbolWithChar("holey"));
    env->SetHoleySymbol(thread_, holeySymbol.GetTaggedValue());
    JSHandle<JSTaggedValue> elementIcSymbol(factory_->NewPrivateNameSymbolWithChar("element-ic"));
    env->SetElementICSymbol(thread_, elementIcSymbol.GetTaggedValue());

    // ecma 19.2.3.6 Function.prototype[@@hasInstance] ( V )
    JSHandle<JSObject> funcFuncPrototypeObj = JSHandle<JSObject>(env->GetFunctionPrototype());
    SetFunctionAtSymbol<JSSymbol::SymbolType::HAS_INSTANCE>(
        env, funcFuncPrototypeObj, env->GetHasInstanceSymbol(), "[Symbol.hasInstance]",
        builtins::function::proto::HasInstance, FunctionLength::ONE);

    SetFunctionsGenSymbol(env, symbolFunction);
    SetFunctionsGenSymbolProto(env, symbolFuncPrototype);
}

void Builtins::InitializeSymbolWithRealm(const JSHandle<GlobalEnv> &realm,
                                         const JSHandle<JSHClass> &objFuncInstanceDynclass)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
    // Symbol.prototype
    JSHandle<JSObject> symbolFuncPrototype = factory_->NewJSObject(objFuncInstanceDynclass);
    JSHandle<JSTaggedValue> symbolFuncPrototypeValue(symbolFuncPrototype);

    // Symbol.prototype_or_dynclass
    JSHandle<JSHClass> symbolFuncInstanceDynclass =
        factory_->CreateDynClass<JSPrimitiveRef>(JSType::JS_PRIMITIVE_REF, symbolFuncPrototypeValue);

    // Symbol = new Function()
    JSHandle<JSObject> symbolFunction(NewBuiltinConstructor(
        realm, symbolFuncPrototype, builtins::symbol::SymbolConstructor, "Symbol", FunctionLength::ZERO));
    JSHandle<JSFunction>(symbolFunction)->SetFunctionPrototype(thread_, symbolFuncInstanceDynclass.GetTaggedValue());

    // "constructor" property on the prototype
    JSHandle<JSTaggedValue> constructorKey = thread_->GlobalConstants()->GetHandledConstructorString();
    PropertyDescriptor descriptor(thread_, JSHandle<JSTaggedValue>::Cast(symbolFunction), true, false, true);
    JSObject::DefineOwnProperty(thread_, symbolFuncPrototype, constructorKey, descriptor);

    // Symbol attribute
    SetNoneAttributeProperty(symbolFunction, "hasInstance", env->GetHasInstanceSymbol());
    SetNoneAttributeProperty(symbolFunction, "isConcatSpreadable", env->GetIsConcatSpreadableSymbol());
    SetNoneAttributeProperty(symbolFunction, "toStringTag", env->GetToStringTagSymbol());
    SetNoneAttributeProperty(symbolFunction, "iterator", env->GetIteratorSymbol());
    SetNoneAttributeProperty(symbolFunction, "asyncIterator", env->GetAsyncIteratorSymbol());
    SetNoneAttributeProperty(symbolFunction, "match", env->GetMatchSymbol());
    SetNoneAttributeProperty(symbolFunction, "matchAll", env->GetMatchAllSymbol());
    SetNoneAttributeProperty(symbolFunction, "replace", env->GetReplaceSymbol());
    SetNoneAttributeProperty(symbolFunction, "search", env->GetSearchSymbol());
    SetNoneAttributeProperty(symbolFunction, "species", env->GetSpeciesSymbol());
    SetNoneAttributeProperty(symbolFunction, "split", env->GetSplitSymbol());
    SetNoneAttributeProperty(symbolFunction, "toPrimitive", env->GetToPrimitiveSymbol());
    SetNoneAttributeProperty(symbolFunction, "unscopables", env->GetUnscopablesSymbol());

    realm->SetSymbolFunction(thread_, symbolFunction);
    realm->SetHasInstanceSymbol(thread_, env->GetHasInstanceSymbol());
    realm->SetIsConcatSpreadableSymbol(thread_, env->GetIsConcatSpreadableSymbol());
    realm->SetToStringTagSymbol(thread_, env->GetToStringTagSymbol());
    realm->SetIteratorSymbol(thread_, env->GetIteratorSymbol());
    realm->SetAsyncIteratorSymbol(thread_, env->GetAsyncIteratorSymbol());
    realm->SetMatchSymbol(thread_, env->GetMatchSymbol());
    realm->SetMatchAllSymbol(thread_, env->GetMatchAllSymbol());
    realm->SetReplaceSymbol(thread_, env->GetReplaceSymbol());
    realm->SetSearchSymbol(thread_, env->GetSearchSymbol());
    realm->SetSpeciesSymbol(thread_, env->GetSpeciesSymbol());
    realm->SetSplitSymbol(thread_, env->GetSplitSymbol());
    realm->SetToPrimitiveSymbol(thread_, env->GetToPrimitiveSymbol());
    realm->SetUnscopablesSymbol(thread_, env->GetUnscopablesSymbol());

    // Setup %SymbolPrototype%
    SetStringTagSymbol(realm, symbolFuncPrototype, "Symbol");

    JSHandle<JSTaggedValue> holeySymbol(factory_->NewPrivateNameSymbolWithChar("holey"));
    realm->SetHoleySymbol(thread_, holeySymbol.GetTaggedValue());
    JSHandle<JSTaggedValue> elementIcSymbol(factory_->NewPrivateNameSymbolWithChar("element-ic"));
    realm->SetElementICSymbol(thread_, elementIcSymbol.GetTaggedValue());

    // ecma 19.2.3.6 Function.prototype[@@hasInstance] ( V )
    JSHandle<JSObject> funcFuncPrototypeObj = JSHandle<JSObject>(realm->GetFunctionPrototype());
    SetFunctionAtSymbol<JSSymbol::SymbolType::HAS_INSTANCE>(
        realm, funcFuncPrototypeObj, realm->GetHasInstanceSymbol(), "[Symbol.hasInstance]",
        builtins::function::proto::HasInstance, FunctionLength::ONE);

    SetFunctionsGenSymbol(realm, symbolFunction);
    SetFunctionsGenSymbolProto(realm, symbolFuncPrototype);
}

void Builtins::InitializeNumber(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &primRefObjDynclass)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Number.prototype
    JSHandle<JSTaggedValue> toObject(thread_, JSTaggedValue(FunctionLength::ZERO));
    JSHandle<JSObject> numFuncPrototype =
        JSHandle<JSObject>::Cast(factory_->NewJSPrimitiveRef(primRefObjDynclass, toObject));
    JSHandle<JSTaggedValue> numFuncPrototypeValue(numFuncPrototype);

    // Number.prototype_or_dynclass
    JSHandle<JSHClass> numFuncInstanceClass =
        factory_->CreateDynClass<JSPrimitiveRef>(JSType::JS_PRIMITIVE_REF, numFuncPrototypeValue);

    // Number = new Function()
    JSHandle<JSObject> numFunction(NewBuiltinConstructor(env, numFuncPrototype, builtins::number::NumberConstructor,
                                                         "Number", FunctionLength::ONE));
    numFunction.GetObject<JSFunction>()->SetFunctionPrototype(thread_, numFuncInstanceClass.GetTaggedValue());

    env->SetNumberFunction(thread_, numFunction);

    // Number method

    // Number constant
    const double epsilon = 2.220446049250313e-16;
    const double maxSafeInteger = 9007199254740991;
    const double maxValue = 1.7976931348623157e+308;
    const double minValue = 5e-324;
    const double positiveInfinity = std::numeric_limits<double>::infinity();
    SetConstant(numFunction, "MAX_VALUE", JSTaggedValue(maxValue));
    SetConstant(numFunction, "MIN_VALUE", JSTaggedValue(minValue));
    SetConstant(numFunction, "NaN", JSTaggedValue(NAN));
    SetConstant(numFunction, "NEGATIVE_INFINITY", JSTaggedValue(-positiveInfinity));
    SetConstant(numFunction, "POSITIVE_INFINITY", JSTaggedValue(positiveInfinity));
    SetConstant(numFunction, "MAX_SAFE_INTEGER", JSTaggedValue(maxSafeInteger));
    SetConstant(numFunction, "MIN_SAFE_INTEGER", JSTaggedValue(-maxSafeInteger));
    SetConstant(numFunction, "EPSILON", JSTaggedValue(epsilon));

    SetFunctionsGenNumberProto(env, numFuncPrototype);

    SetFunctionsGenNumber(env, numFunction);
}

void Builtins::InitializeBigInt(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // BigInt.prototype
    JSHandle<JSObject> bigIntFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> bigIntFuncPrototypeValue(bigIntFuncPrototype);

    // BigInt.prototype_or_dynclass
    JSHandle<JSHClass> bigIntFuncInstanceDynclass =
        factory_->CreateDynClass<JSPrimitiveRef>(JSType::JS_PRIMITIVE_REF, bigIntFuncPrototypeValue);
    // BigInt = new Function()
    JSHandle<JSObject> bigIntFunction(NewBuiltinConstructor(
        env, bigIntFuncPrototype, builtins::big_int::BigIntConstructor, "BigInt", FunctionLength::ONE));
    JSHandle<JSFunction>(bigIntFunction)->SetFunctionPrototype(thread_, bigIntFuncInstanceDynclass.GetTaggedValue());

    env->SetBigIntFunction(thread_, bigIntFunction);

    // @@ToStringTag
    SetStringTagSymbol(env, bigIntFuncPrototype, "BigInt");
    SetFunctionsGenBigIntProto(env, bigIntFuncPrototype);
    SetFunctionsGenBigInt(env, bigIntFunction);
}

void Builtins::InitializeDate(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const int utcLength = 7;
    // Date.prototype
    JSHandle<JSObject> dateFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> dateFuncPrototypeValue(dateFuncPrototype);

    // Date.prototype_or_dynclass
    JSHandle<JSHClass> dateFuncInstanceDynclass =
        factory_->CreateDynClass<JSDate>(JSType::JS_DATE, dateFuncPrototypeValue);

    // Date = new Function()
    JSHandle<JSObject> dateFunction(
        NewBuiltinConstructor(env, dateFuncPrototype, builtins::date::DateConstructor, "Date", FunctionLength::ONE));
    JSHandle<JSFunction>(dateFunction)->SetFunctionPrototype(thread_, dateFuncInstanceDynclass.GetTaggedValue());

    env->SetDateFunction(thread_, dateFunction);

    // Date.length
    SetConstant(dateFunction, "length", JSTaggedValue(utcLength));
    SetFunctionsGenDateProto(env, dateFuncPrototype);

    SetFunctionsGenDate(env, dateFunction);
}

void Builtins::InitializeBoolean(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &primRefObjDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Boolean.prototype
    JSHandle<JSTaggedValue> toObject(thread_, JSTaggedValue::False());
    JSHandle<JSObject> booleanFuncPrototype =
        JSHandle<JSObject>::Cast(factory_->NewJSPrimitiveRef(primRefObjDynclass, toObject));
    JSHandle<JSTaggedValue> booleanFuncPrototypeValue(booleanFuncPrototype);

    // Boolean.prototype_or_dynclass
    JSHandle<JSHClass> booleanFuncInstanceDynclass =
        factory_->CreateDynClass<JSPrimitiveRef>(JSType::JS_PRIMITIVE_REF, booleanFuncPrototypeValue);

    // new Boolean Function()
    JSHandle<JSFunction> booleanFunction(NewBuiltinConstructor(
        env, booleanFuncPrototype, builtins::boolean::BooleanConstructor, "Boolean", FunctionLength::ONE));
    booleanFunction->SetFunctionPrototype(thread_, booleanFuncInstanceDynclass.GetTaggedValue());

    env->SetBooleanFunction(thread_, booleanFunction);
    SetFunctionsGenBooleanProto(env, booleanFuncPrototype);
}

void Builtins::InitializeProxy(const JSHandle<GlobalEnv> &env)
{
    JSHandle<JSObject> proxyFunction(InitializeExoticConstructor(env, builtins::proxy::ProxyConstructor, "Proxy", 2));
    env->SetProxyFunction(thread_, proxyFunction);
    SetFunctionsGenProxy(env, proxyFunction);
}

JSHandle<JSFunction> Builtins::InitializeExoticConstructor(const JSHandle<GlobalEnv> &env, EcmaEntrypoint ctorFunc,
                                                           const char *name, int length)
{
    JSHandle<JSFunction> ctor =
        factory_->NewJSFunction(env, reinterpret_cast<void *>(ctorFunc), FunctionKind::BUILTIN_PROXY_CONSTRUCTOR);

    JSFunction::SetFunctionLength(thread_, ctor, JSTaggedValue(length));
    JSHandle<JSTaggedValue> nameString(factory_->NewFromString(name));
    JSFunction::SetFunctionName(thread_, JSHandle<JSFunctionBase>(ctor), nameString,
                                JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()));

    JSHandle<JSObject> globalObject(thread_, env->GetGlobalObject());
    PropertyDescriptor descriptor(thread_, JSHandle<JSTaggedValue>(ctor), true, false, true);
    JSObject::DefineOwnProperty(thread_, globalObject, nameString, descriptor);
    return ctor;
}

void Builtins::InitializeAsyncFunction(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    // AsyncFunction.prototype
    JSHandle<JSObject> asyncFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSObject::SetPrototype(thread_, asyncFuncPrototype, env->GetFunctionPrototype());
    JSHandle<JSTaggedValue> asyncFuncPrototypeValue(asyncFuncPrototype);

    // AsyncFunction.prototype_or_dynclass
    JSHandle<JSHClass> asyncFuncInstanceDynclass =
        factory_->CreateDynClass<JSAsyncFunction>(JSType::JS_ASYNC_FUNCTION, asyncFuncPrototypeValue);

    // AsyncFunction = new Function()
    JSHandle<JSFunction> asyncFunction =
        NewBuiltinConstructor(env, asyncFuncPrototype, builtins::async_function::AsyncFunctionConstructor,
                              "AsyncFunction", FunctionLength::ONE);
    JSObject::SetPrototype(thread_, JSHandle<JSObject>::Cast(asyncFunction), env->GetFunctionFunction());
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    PropertyDescriptor asyncDesc(thread_, JSHandle<JSTaggedValue>::Cast(asyncFunction), false, false, true);
    JSObject::DefineOwnProperty(thread_, asyncFuncPrototype, constructorKey, asyncDesc);
    asyncFunction->SetProtoOrDynClass(thread_, asyncFuncInstanceDynclass.GetTaggedValue());

    // AsyncFunction.prototype property
    SetStringTagSymbol(env, asyncFuncPrototype, "AsyncFunction");
    env->SetAsyncFunction(thread_, asyncFunction);
    env->SetAsyncFunctionPrototype(thread_, asyncFuncPrototype);
}

void Builtins::InitializeAllTypeError(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    // Error.prototype
    JSHandle<JSObject> errorFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> errorFuncPrototypeValue(errorFuncPrototype);
    // Error.prototype_or_dynclass
    JSHandle<JSHClass> errorFuncInstanceDynclass =
        factory_->CreateDynClass<JSObject>(JSType::JS_ERROR, errorFuncPrototypeValue);
    // Error() = new Function()
    JSHandle<JSFunction> errorFunction(NewBuiltinConstructor(env, errorFuncPrototype, builtins::error::ErrorConstructor,
                                                             "Error", FunctionLength::ONE));
    errorFunction->SetFunctionPrototype(thread_, errorFuncInstanceDynclass.GetTaggedValue());
    env->SetErrorFunction(thread_, errorFunction);

    // Error.prototype Attribute
    SetAttribute(errorFuncPrototype, "name", "Error");
    SetAttribute(errorFuncPrototype, "message", "");

    SetFunctionsGenErrorProto(env, errorFuncPrototype);

    JSHandle<JSHClass> nativeErrorFuncClass = factory_->CreateDynClass<JSFunction>(
        JSType::JS_FUNCTION, env->GetErrorFunction(), HClass::IS_CALLABLE | HClass::IS_BUILTINS_CTOR);
    nativeErrorFuncClass->SetConstructor(true);
    env->SetNativeErrorFunctionClass(thread_, nativeErrorFuncClass);

    JSHandle<JSHClass> errorNativeFuncInstanceDynclass =
        factory_->CreateDynClass<JSObject>(JSType::JS_OBJECT, errorFuncPrototypeValue);
    InitializeError(env, errorNativeFuncInstanceDynclass, JSType::JS_RANGE_ERROR);
    InitializeError(env, errorNativeFuncInstanceDynclass, JSType::JS_REFERENCE_ERROR);
    InitializeError(env, errorNativeFuncInstanceDynclass, JSType::JS_TYPE_ERROR);
    InitializeError(env, errorNativeFuncInstanceDynclass, JSType::JS_URI_ERROR);
    InitializeError(env, errorNativeFuncInstanceDynclass, JSType::JS_SYNTAX_ERROR);
    InitializeError(env, errorNativeFuncInstanceDynclass, JSType::JS_EVAL_ERROR);
}

void Builtins::InitializeAllTypeErrorWithRealm(const JSHandle<GlobalEnv> &realm) const
{
    JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();

    realm->SetErrorFunction(thread_, env->GetErrorFunction());
    realm->SetNativeErrorFunctionClass(thread_, env->GetNativeErrorFunctionClass());

    SetErrorWithRealm(realm, JSType::JS_RANGE_ERROR);
    SetErrorWithRealm(realm, JSType::JS_REFERENCE_ERROR);
    SetErrorWithRealm(realm, JSType::JS_TYPE_ERROR);
    SetErrorWithRealm(realm, JSType::JS_URI_ERROR);
    SetErrorWithRealm(realm, JSType::JS_SYNTAX_ERROR);
    SetErrorWithRealm(realm, JSType::JS_EVAL_ERROR);
}

void Builtins::SetErrorWithRealm(const JSHandle<GlobalEnv> &realm, const JSType &errorTag) const
{
    JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
    JSHandle<JSObject> globalObject(thread_, realm->GetGlobalObject());
    JSHandle<JSTaggedValue> nameString;
    JSHandle<JSTaggedValue> nativeErrorFunction;
    switch (errorTag) {
        case JSType::JS_RANGE_ERROR:
            nativeErrorFunction = env->GetRangeErrorFunction();
            nameString = JSHandle<JSTaggedValue>(thread_->GlobalConstants()->GetHandledRangeErrorString());
            realm->SetRangeErrorFunction(thread_, nativeErrorFunction);
            break;
        case JSType::JS_EVAL_ERROR:
            nativeErrorFunction = env->GetEvalErrorFunction();
            nameString = JSHandle<JSTaggedValue>(thread_->GlobalConstants()->GetHandledEvalErrorString());
            realm->SetEvalErrorFunction(thread_, nativeErrorFunction);
            break;
        case JSType::JS_REFERENCE_ERROR:
            nativeErrorFunction = env->GetReferenceErrorFunction();
            nameString = JSHandle<JSTaggedValue>(thread_->GlobalConstants()->GetHandledReferenceErrorString());
            realm->SetReferenceErrorFunction(thread_, nativeErrorFunction);
            break;
        case JSType::JS_TYPE_ERROR:
            nativeErrorFunction = env->GetTypeErrorFunction();
            nameString = JSHandle<JSTaggedValue>(thread_->GlobalConstants()->GetHandledTypeErrorString());
            realm->SetTypeErrorFunction(thread_, nativeErrorFunction);
            realm->SetThrowTypeError(thread_, env->GetThrowTypeError());
            break;
        case JSType::JS_URI_ERROR:
            nativeErrorFunction = env->GetURIErrorFunction();
            nameString = JSHandle<JSTaggedValue>(thread_->GlobalConstants()->GetHandledURIErrorString());
            realm->SetURIErrorFunction(thread_, nativeErrorFunction);
            break;
        case JSType::JS_SYNTAX_ERROR:
            nativeErrorFunction = env->GetSyntaxErrorFunction();
            nameString = JSHandle<JSTaggedValue>(thread_->GlobalConstants()->GetHandledSyntaxErrorString());
            realm->SetSyntaxErrorFunction(thread_, nativeErrorFunction);
            break;
        default:
            break;
    }
    PropertyDescriptor descriptor(thread_, nativeErrorFunction, true, false, true);
    JSObject::DefineOwnProperty(thread_, globalObject, nameString, descriptor);
}

void Builtins::GeneralUpdateError(ErrorParameter *error, EcmaEntrypoint constructor, EcmaEntrypoint method,
                                  const char *name, JSType type) const
{
    error->nativeConstructor = constructor;
    error->nativeMethod = method;
    error->nativePropertyName = name;
    error->nativeJstype = type;
}

// NOTE(dkofanov): Split errors initialization, use `SetFunctionsGenRangeErrorProto` from `builtins_initializers_gen.h`
// and etc.
void Builtins::InitializeError(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass,
                               const JSType &errorTag) const
{
    // NativeError.prototype
    JSHandle<JSObject> nativeErrorFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> nativeErrorFuncPrototypeValue(nativeErrorFuncPrototype);

    ErrorParameter errorParameter {builtins::range_error::RangeErrorConstructor, builtins::range_error::proto::ToString,
                                   "RangeError", JSType::JS_RANGE_ERROR};
    switch (errorTag) {
        case JSType::JS_RANGE_ERROR:
            GeneralUpdateError(&errorParameter, builtins::range_error::RangeErrorConstructor,
                               builtins::range_error::proto::ToString, "RangeError", JSType::JS_RANGE_ERROR);
            break;
        case JSType::JS_EVAL_ERROR:
            GeneralUpdateError(&errorParameter, builtins::eval_error::EvalErrorConstructor,
                               builtins::eval_error::proto::ToString, "EvalError", JSType::JS_EVAL_ERROR);
            break;
        case JSType::JS_REFERENCE_ERROR:
            GeneralUpdateError(&errorParameter, builtins::reference_error::ReferenceErrorConstructor,
                               builtins::reference_error::proto::ToString, "ReferenceError",
                               JSType::JS_REFERENCE_ERROR);
            break;
        case JSType::JS_TYPE_ERROR:
            GeneralUpdateError(&errorParameter, builtins::type_error::TypeErrorConstructor,
                               builtins::type_error::proto::ToString, "TypeError", JSType::JS_TYPE_ERROR);
            break;
        case JSType::JS_URI_ERROR:
            GeneralUpdateError(&errorParameter, builtins::uri_error::URIErrorConstructor,
                               builtins::uri_error::proto::ToString, "URIError", JSType::JS_URI_ERROR);
            break;
        case JSType::JS_SYNTAX_ERROR:
            GeneralUpdateError(&errorParameter, builtins::syntax_error::SyntaxErrorConstructor,
                               builtins::syntax_error::proto::ToString, "SyntaxError", JSType::JS_SYNTAX_ERROR);
            break;
        default:
            break;
    }

    // NativeError.prototype_or_dynclass
    JSHandle<JSHClass> nativeErrorFuncInstanceDynclass =
        factory_->CreateDynClass<JSObject>(errorParameter.nativeJstype, nativeErrorFuncPrototypeValue);

    // NativeError() = new Error()
    JSHandle<JSFunction> nativeErrorFunction =
        factory_->NewJSNativeErrorFunction(env, reinterpret_cast<void *>(errorParameter.nativeConstructor));
    InitializeCtor(env, nativeErrorFuncPrototype, nativeErrorFunction, errorParameter.nativePropertyName,
                   FunctionLength::ONE);

    nativeErrorFunction->SetFunctionPrototype(thread_, nativeErrorFuncInstanceDynclass.GetTaggedValue());

    // NativeError.prototype method
    SetFunction(env, nativeErrorFuncPrototype, thread_->GlobalConstants()->GetHandledToStringString(),
                errorParameter.nativeMethod, FunctionLength::ZERO);

    // Error.prototype Attribute
    SetAttribute(nativeErrorFuncPrototype, "name", errorParameter.nativePropertyName);
    SetAttribute(nativeErrorFuncPrototype, "message", "");

    if (errorTag == JSType::JS_RANGE_ERROR) {
        env->SetRangeErrorFunction(thread_, nativeErrorFunction);
    } else if (errorTag == JSType::JS_REFERENCE_ERROR) {
        env->SetReferenceErrorFunction(thread_, nativeErrorFunction);
    } else if (errorTag == JSType::JS_TYPE_ERROR) {
        env->SetTypeErrorFunction(thread_, nativeErrorFunction);
        JSHandle<JSFunction> throwTypeErrorFunction =
            factory_->NewJSFunction(env, reinterpret_cast<void *>(type_error::ThrowTypeError));
        JSFunction::SetFunctionLength(thread_, throwTypeErrorFunction, JSTaggedValue(1), false);
        JSObject::PreventExtensions(thread_, JSHandle<JSObject>::Cast(throwTypeErrorFunction));
        env->SetThrowTypeError(thread_, throwTypeErrorFunction);
    } else if (errorTag == JSType::JS_URI_ERROR) {
        env->SetURIErrorFunction(thread_, nativeErrorFunction);
    } else if (errorTag == JSType::JS_SYNTAX_ERROR) {
        env->SetSyntaxErrorFunction(thread_, nativeErrorFunction);
    } else {
        env->SetEvalErrorFunction(thread_, nativeErrorFunction);
    }
}  // namespace ark::ecmascript

void Builtins::InitializeCtor(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &prototype,
                              const JSHandle<JSFunction> &ctor, const char *name, int length) const
{
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    JSFunction::SetFunctionLength(thread_, ctor, JSTaggedValue(length));
    JSHandle<JSTaggedValue> nameString(factory_->NewFromString(name));
    JSFunction::SetFunctionName(thread_, JSHandle<JSFunctionBase>(ctor), nameString,
                                JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()));
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    PropertyDescriptor descriptor1(thread_, JSHandle<JSTaggedValue>::Cast(ctor), true, false, true);
    JSObject::DefineOwnProperty(thread_, prototype, constructorKey, descriptor1);

    /* set "prototype" in constructor */
    ctor->SetFunctionPrototype(thread_, prototype.GetTaggedValue());

    if (!JSTaggedValue::SameValue(nameString, thread_->GlobalConstants()->GetHandledAsyncFunctionString())) {
        JSHandle<JSObject> globalObject(thread_, env->GetGlobalObject());
        PropertyDescriptor descriptor2(thread_, JSHandle<JSTaggedValue>::Cast(ctor), true, false, true);
        JSObject::DefineOwnProperty(thread_, globalObject, nameString, descriptor2);
    }
}

void Builtins::InitializeSet(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    // Set.prototype
    JSHandle<JSObject> setFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> setFuncPrototypeValue(setFuncPrototype);
    // Set.prototype_or_dynclass
    JSHandle<JSHClass> setFuncInstanceDynclass = factory_->CreateDynClass<JSSet>(JSType::JS_SET, setFuncPrototypeValue);
    // Set() = new Function()
    JSHandle<JSTaggedValue> setFunction(
        NewBuiltinConstructor(env, setFuncPrototype, builtins::set::SetConstructor, "Set", FunctionLength::ZERO));
    JSHandle<JSFunction>(setFunction)->SetFunctionPrototype(thread_, setFuncInstanceDynclass.GetTaggedValue());

    // "constructor" property on the prototype
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(setFuncPrototype), constructorKey, setFunction);

    env->SetSetFunction(thread_, setFunction);
    env->SetSetPrototype(thread_, setFuncPrototype);

    // @@ToStringTag
    SetStringTagSymbol(env, setFuncPrototype, "Set");

    SetFunctionsGenSetProto(env, setFuncPrototype);

    SetFunctionsGenSet(env, JSHandle<JSObject>(setFunction));
}

void Builtins::InitializeMap(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    // Map.prototype
    JSHandle<JSObject> mapFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> mapFuncPrototypeValue(mapFuncPrototype);

    // Map.prototype_or_dynclass
    JSHandle<JSHClass> mapFuncInstanceDynclass = factory_->CreateDynClass<JSMap>(JSType::JS_MAP, mapFuncPrototypeValue);
    // Map() = new Function()
    JSHandle<JSTaggedValue> mapFunction(
        NewBuiltinConstructor(env, mapFuncPrototype, map::MapConstructor, "Map", FunctionLength::ZERO));
    // Map().prototype = Map.Prototype & Map.prototype.constructor = Map()
    JSFunction::Cast(mapFunction->GetTaggedObject())
        ->SetFunctionPrototype(thread_, mapFuncInstanceDynclass.GetTaggedValue());

    // "constructor" property on the prototype
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(mapFuncPrototype), constructorKey, mapFunction);

    env->SetMapFunction(thread_, mapFunction);
    env->SetMapPrototype(thread_, mapFuncPrototype);
    SetFunctionsGenMapProto(env, mapFuncPrototype);
    SetFunctionsGenMap(env, JSHandle<JSObject>(mapFunction));

    // @@ToStringTag
    SetStringTagSymbol(env, mapFuncPrototype, "Map");
}

void Builtins::InitializeWeakRef(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    // WeakRef.prototype
    JSHandle<JSObject> weakRefFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> weakRefFuncPrototypeValue(weakRefFuncPrototype);
    // WeakRef.prototype_or_dynclass
    JSHandle<JSHClass> weakRefFuncInstanceDynclass =
        factory_->CreateDynClass<JSWeakRef>(JSType::JS_WEAK_REF, weakRefFuncPrototypeValue);
    weakRefFuncInstanceDynclass->SetWeakContainer(true);
    // WeakRef() = new Function()
    JSHandle<JSTaggedValue> weakRefFunction(
        NewBuiltinConstructor(env, weakRefFuncPrototype, weak_ref::Constructor, "WeakRef", FunctionLength::ONE));
    // WeakRef().prototype = WeakRef.Prototype & WeakRef.prototype.constructor = WeakRef()
    JSFunction::Cast(weakRefFunction->GetTaggedObject())
        ->SetProtoOrDynClass(thread_, weakRefFuncInstanceDynclass.GetTaggedValue());

    // "constructor" property on the prototype
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(weakRefFuncPrototype), constructorKey, weakRefFunction);
    SetFunctionsGenWeakRefProto(env, weakRefFuncPrototype);
    // @@ToStringTag
    SetStringTagSymbol(env, weakRefFuncPrototype, "WeakRef");
}

void Builtins::InitializeWeakMap(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    // WeakMap.prototype
    JSHandle<JSObject> weakMapFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> weakMapFuncPrototypeValue(weakMapFuncPrototype);
    // WeakMap.prototype_or_dynclass
    JSHandle<JSHClass> weakMapFuncInstanceDynclass =
        factory_->CreateDynClass<JSWeakMap>(JSType::JS_WEAK_MAP, weakMapFuncPrototypeValue);
    // WeakMap() = new Function()
    JSHandle<JSTaggedValue> weakMapFunction(NewBuiltinConstructor(
        env, weakMapFuncPrototype, weak_map::WeakMapConstructor, "WeakMap", FunctionLength::ZERO));
    // WeakMap().prototype = WeakMap.Prototype & WeakMap.prototype.constructor = WeakMap()
    JSFunction::Cast(weakMapFunction->GetTaggedObject())
        ->SetProtoOrDynClass(thread_, weakMapFuncInstanceDynclass.GetTaggedValue());

    // "constructor" property on the prototype
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(weakMapFuncPrototype), constructorKey, weakMapFunction);
    env->SetWeakMapFunction(thread_, weakMapFunction);
    SetFunctionsGenWeakMapProto(env, weakMapFuncPrototype);
    // @@ToStringTag
    SetStringTagSymbol(env, weakMapFuncPrototype, "WeakMap");
}

void Builtins::InitializeWeakSet(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    // Set.prototype
    JSHandle<JSObject> weakSetFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> weakSetFuncPrototypeValue(weakSetFuncPrototype);
    // Set.prototype_or_dynclass
    JSHandle<JSHClass> weakSetFuncInstanceDynclass =
        factory_->CreateDynClass<JSWeakSet>(JSType::JS_WEAK_SET, weakSetFuncPrototypeValue);
    // Set() = new Function()
    JSHandle<JSTaggedValue> weakSetFunction(NewBuiltinConstructor(
        env, weakSetFuncPrototype, weak_set::WeakSetConstructor, "WeakSet", FunctionLength::ZERO));
    JSHandle<JSFunction>(weakSetFunction)->SetProtoOrDynClass(thread_, weakSetFuncInstanceDynclass.GetTaggedValue());

    // "constructor" property on the prototype
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(weakSetFuncPrototype), constructorKey, weakSetFunction);

    env->SetWeakSetFunction(thread_, weakSetFunction);
    SetFunctionsGenWeakSetProto(env, weakSetFuncPrototype);
    // @@ToStringTag
    SetStringTagSymbol(env, weakSetFuncPrototype, "WeakSet");
}

void Builtins::InitializeMath(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    JSHandle<JSHClass> mathDynclass = factory_->CreateDynClass<JSObject>(JSType::JS_OBJECT, objFuncPrototypeVal);
    JSHandle<JSObject> mathObject = factory_->NewJSObject(mathDynclass);

    env->SetMathFunction(thread_, mathObject);
    SetFunctionsGenMath(env, mathObject);

    SetConstant(mathObject, "E", math::GetPropE());
    SetConstant(mathObject, "LN10", math::GetPropLN10());
    SetConstant(mathObject, "LN2", math::GetPropLN2());
    SetConstant(mathObject, "LOG10E", math::GetPropLOG10E());
    SetConstant(mathObject, "LOG2E", math::GetPropLOG2E());
    SetConstant(mathObject, "PI", math::GetPropPI());
    SetConstant(mathObject, "SQRT1_2", math::GetPropSQRT1_2());
    SetConstant(mathObject, "SQRT2", math::GetPropSQRT2());

    JSHandle<JSTaggedValue> mathString(factory_->NewFromCanBeCompressString("Math"));
    JSHandle<JSObject> globalObject(thread_, env->GetGlobalObject());
    PropertyDescriptor mathDesc(thread_, JSHandle<JSTaggedValue>::Cast(mathObject), true, false, true);
    JSObject::DefineOwnProperty(thread_, globalObject, mathString, mathDesc);
    // @@ToStringTag
    SetStringTagSymbol(env, mathObject, "Math");
}

void Builtins::InitializeJson(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    JSHandle<JSHClass> jsonDynclass = factory_->CreateDynClass<JSObject>(JSType::JS_OBJECT, objFuncPrototypeVal);
    JSHandle<JSObject> jsonObject = factory_->NewJSObject(jsonDynclass);

    env->SetJsonFunction(thread_, jsonObject);
    SetFunctionsGenJson(env, jsonObject);

    PropertyDescriptor jsonDesc(thread_, JSHandle<JSTaggedValue>::Cast(jsonObject), true, false, true);
    JSHandle<JSTaggedValue> jsonString(factory_->NewFromCanBeCompressString("JSON"));
    JSHandle<JSObject> globalObject(thread_, env->GetGlobalObject());
    JSObject::DefineOwnProperty(thread_, globalObject, jsonString, jsonDesc);
    // @@ToStringTag
    SetStringTagSymbol(env, jsonObject, "JSON");
}

void Builtins::InitializeString(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &primRefObjDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // String.prototype
    JSHandle<JSTaggedValue> toObject(factory_->GetEmptyString());
    JSHandle<JSObject> stringFuncPrototype =
        JSHandle<JSObject>::Cast(factory_->NewJSPrimitiveRef(primRefObjDynclass, toObject));
    JSHandle<JSTaggedValue> stringFuncPrototypeValue(stringFuncPrototype);

    // String.prototype_or_dynclass
    JSHandle<JSHClass> stringFuncInstanceDynclass =
        factory_->CreateDynClass<JSPrimitiveRef>(JSType::JS_PRIMITIVE_REF, stringFuncPrototypeValue);

    // String = new Function()
    JSHandle<JSObject> stringFunction(
        NewBuiltinConstructor(env, stringFuncPrototype, string::StringConstructor, "String", FunctionLength::ONE));
    stringFunction.GetObject<JSFunction>()->SetFunctionPrototype(thread_, stringFuncInstanceDynclass.GetTaggedValue());

    env->SetStringFunction(thread_, stringFunction);
    env->SetStringPrototype(thread_, stringFuncPrototype);

    SetFunctionsGenString(env, stringFunction);
    SetFunctionsGenStringProto(env, stringFuncPrototype);
}

void Builtins::InitializeStringIterator(const JSHandle<GlobalEnv> &env,
                                        const JSHandle<JSHClass> &iteratorFuncDynclass) const
{
    // StringIterator.prototype
    JSHandle<JSObject> strIterPrototype(factory_->NewJSObject(iteratorFuncDynclass));

    // StringIterator.prototype_or_dynclass
    JSHandle<JSHClass> strIterFuncInstanceDynclass = factory_->CreateDynClass<JSStringIterator>(
        JSType::JS_STRING_ITERATOR, JSHandle<JSTaggedValue>(strIterPrototype));

    JSHandle<JSFunction> strIterFunction(
        factory_->NewJSFunction(env, static_cast<void *>(nullptr), FunctionKind::BASE_CONSTRUCTOR));
    strIterFunction->SetFunctionPrototype(thread_, strIterFuncInstanceDynclass.GetTaggedValue());

    env->SetStringIteratorFunction(thread_, strIterFunction);
    env->SetStringIteratorPrototype(thread_, strIterPrototype);
    SetFunctionsGenStringIteratorProto(env, strIterPrototype);
    SetStringTagSymbol(env, strIterPrototype, "String Iterator");
}

void Builtins::InitializeIterator(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Iterator.prototype
    JSHandle<JSObject> iteratorPrototype = factory_->NewJSObject(objFuncDynclass);

    env->SetIteratorPrototype(thread_, iteratorPrototype);
    SetFunctionsGenIteratorProto(env, iteratorPrototype);

    // Iterator.dynclass
    JSHandle<JSHClass> iteratorFuncDynclass =
        factory_->CreateDynClass<JSObject>(JSType::JS_ITERATOR, JSHandle<JSTaggedValue>(iteratorPrototype));

    InitializeForinIterator(env, iteratorFuncDynclass);
    InitializeSetIterator(env, iteratorFuncDynclass);
    InitializeMapIterator(env, iteratorFuncDynclass);
    InitializeArrayIterator(env, iteratorFuncDynclass);
    InitializeStringIterator(env, iteratorFuncDynclass);
    InitializeRegexpIterator(env, iteratorFuncDynclass);
}

void Builtins::InitializeAsyncIterator(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // AsyncIterator.prototype
    JSHandle<JSObject> asyncIteratorPrototype = factory_->NewJSObject(objFuncDynclass);

    SetFunctionsGenAsyncIteratorProto(env, asyncIteratorPrototype);

    env->SetAsyncIteratorPrototype(thread_, asyncIteratorPrototype);
}

void Builtins::InitializeForinIterator(const JSHandle<GlobalEnv> &env,
                                       const JSHandle<JSHClass> &iteratorFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Iterator.prototype
    JSHandle<JSObject> forinIteratorPrototype = factory_->NewJSObject(iteratorFuncDynclass);
    JSHandle<JSHClass> dynclass = factory_->CreateDynClass<JSForInIterator>(
        JSType::JS_FORIN_ITERATOR, JSHandle<JSTaggedValue>(forinIteratorPrototype));

    env->SetForinIteratorPrototype(thread_, forinIteratorPrototype);
    env->SetForinIteratorClass(thread_, dynclass);
    SetFunctionsGenForInIteratorProto(env, forinIteratorPrototype);
}

void Builtins::InitializeSetIterator(const JSHandle<GlobalEnv> &env,
                                     const JSHandle<JSHClass> &iteratorFuncDynclass) const
{
    // SetIterator.prototype
    JSHandle<JSObject> setIteratorPrototype(factory_->NewJSObject(iteratorFuncDynclass));

    SetFunctionsGenSetIteratorProto(env, setIteratorPrototype);
    SetStringTagSymbol(env, setIteratorPrototype, "Set Iterator");
    env->SetSetIteratorPrototype(thread_, setIteratorPrototype);
}

void Builtins::InitializeMapIterator(const JSHandle<GlobalEnv> &env,
                                     const JSHandle<JSHClass> &iteratorFuncDynclass) const
{
    // MapIterator.prototype
    JSHandle<JSObject> mapIteratorPrototype(factory_->NewJSObject(iteratorFuncDynclass));
    SetFunctionsGenMapIteratorProto(env, mapIteratorPrototype);

    SetStringTagSymbol(env, mapIteratorPrototype, "Map Iterator");
    env->SetMapIteratorPrototype(thread_, mapIteratorPrototype);
}

void Builtins::InitializeArrayIterator(const JSHandle<GlobalEnv> &env,
                                       const JSHandle<JSHClass> &iteratorFuncDynclass) const
{
    // ArrayIterator.prototype
    JSHandle<JSObject> arrayIteratorPrototype(factory_->NewJSObject(iteratorFuncDynclass));

    SetFunctionsGenArrayIteratorProto(env, arrayIteratorPrototype);
    SetStringTagSymbol(env, arrayIteratorPrototype, "Array Iterator");
    env->SetArrayIteratorPrototype(thread_, arrayIteratorPrototype);
}

void Builtins::InitializeRegexpIterator(const JSHandle<GlobalEnv> &env,
                                        const JSHandle<JSHClass> &iteratorFuncClass) const
{
    // RegExpIterator.prototype
    JSHandle<JSObject> regExpIteratorPrototype(factory_->NewJSObject(iteratorFuncClass));

    SetFunctionsGenRegExpIteratorProto(env, regExpIteratorPrototype);
    SetStringTagSymbol(env, regExpIteratorPrototype, "RegExp String Iterator");
    env->SetRegExpIteratorPrototype(thread_, regExpIteratorPrototype);
}

void Builtins::InitializeRegExp(const JSHandle<GlobalEnv> &env)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // RegExp.prototype
    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
    JSHandle<JSObject> regPrototype = factory_->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
    JSHandle<JSTaggedValue> regPrototypeValue(regPrototype);

    // RegExp.prototype_or_dynclass
    JSHandle<JSHClass> regexpFuncInstanceDynclass = factory_->CreateJSRegExpInstanceClass(regPrototypeValue);

    // RegExp = new Function()
    JSHandle<JSObject> regexpFunction(
        NewBuiltinConstructor(env, regPrototype, reg_exp::RegExpConstructor, "RegExp", FunctionLength::TWO));

    JSHandle<JSFunction>(regexpFunction)->SetFunctionPrototype(thread_, regexpFuncInstanceDynclass.GetTaggedValue());

    SetFunctionsGenRegExpProto(env, regPrototype);
    SetFunctionsGenRegExp(env, regexpFunction);

    env->SetRegExpFunction(thread_, regexpFunction);
    auto globalConst = const_cast<GlobalEnvConstants *>(thread_->GlobalConstants());
    globalConst->SetConstant(ConstantIndex::JS_REGEXP_CLASS_INDEX, regexpFuncInstanceDynclass.GetTaggedValue());
}

void Builtins::InitializeArray(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Arraybase.prototype
    JSHandle<JSHClass> arrBaseFuncInstanceDynclass = factory_->CreateJSArrayInstanceClass(objFuncPrototypeVal);

    // Array.prototype
    JSHandle<JSObject> arrFuncPrototype = factory_->NewJSObject(arrBaseFuncInstanceDynclass);
    JSHandle<JSArray>::Cast(arrFuncPrototype)->SetLength(thread_, JSTaggedValue(FunctionLength::ZERO));
    auto accessor = thread_->GlobalConstants()->GetArrayLengthAccessor();
    JSArray::Cast(*arrFuncPrototype)->SetPropertyInlinedProps(thread_, JSArray::LENGTH_INLINE_PROPERTY_INDEX, accessor);
    JSHandle<JSTaggedValue> arrFuncPrototypeValue(arrFuncPrototype);

    //  Array.prototype_or_dynclass
    JSHandle<JSHClass> arrFuncInstanceDynclass = factory_->CreateJSArrayInstanceClass(arrFuncPrototypeValue);

    // Array = new Function()
    JSHandle<JSObject> arrayFunction(
        NewBuiltinConstructor(env, arrFuncPrototype, builtins::array::ArrayConstructor, "Array", FunctionLength::ONE));
    JSHandle<JSFunction> arrayFuncFunction(arrayFunction);

    // Set the [[Realm]] internal slot of F to the running execution context's Realm
    JSHandle<LexicalEnv> lexicalEnv = factory_->NewLexicalEnv(0);
    lexicalEnv->SetParentEnv(thread_, env.GetTaggedValue());
    arrayFuncFunction->SetLexicalEnv(thread_, lexicalEnv.GetTaggedValue());

    arrayFuncFunction->SetFunctionPrototype(thread_, arrFuncInstanceDynclass.GetTaggedValue());

    env->SetArrayFunction(thread_, arrayFunction);
    env->SetArrayPrototype(thread_, arrFuncPrototype);

    SetFunctionsGenArrayProto(env, arrFuncPrototype);

    SetFunctionsGenArray(env, arrayFunction);

    const int arrProtoLen = 0;
    JSHandle<JSTaggedValue> keyString = thread_->GlobalConstants()->GetHandledLengthString();
    PropertyDescriptor descriptor(thread_, JSHandle<JSTaggedValue>(thread_, JSTaggedValue(arrProtoLen)), true, false,
                                  false);
    JSObject::DefineOwnProperty(thread_, arrFuncPrototype, keyString, descriptor);

    JSHandle<JSTaggedValue> valuesKey(factory_->NewFromCanBeCompressString("values"));
    PropertyDescriptor desc(thread_);
    JSObject::GetOwnProperty(thread_, arrFuncPrototype, valuesKey, desc);

    env->SetArrayProtoValuesFunction(thread_, desc.GetValue());
}

void Builtins::InitializeTypedArray(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // TypedArray.prototype
    JSHandle<JSObject> typedArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> typedArrFuncPrototypeValue(typedArrFuncPrototype);

    // TypedArray.prototype_or_dynclass
    JSHandle<JSHClass> typedArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_TYPED_ARRAY, typedArrFuncPrototypeValue);

    // TypedArray = new Function()
    JSHandle<JSObject> typedArrayFunction(NewBuiltinConstructor(
        env, typedArrFuncPrototype, typed_array::TypedArrayBaseConstructor, "TypedArray", FunctionLength::ZERO));

    JSHandle<JSFunction>(typedArrayFunction)
        ->SetProtoOrDynClass(thread_, typedArrFuncInstanceDynclass.GetTaggedValue());

    env->SetTypedArrayFunction(thread_, typedArrayFunction.GetTaggedValue());
    env->SetTypedArrayPrototype(thread_, typedArrFuncPrototype);

    JSHandle<JSHClass> specificTypedArrayFuncClass = factory_->CreateDynClass<JSFunction>(
        JSType::JS_FUNCTION, env->GetTypedArrayFunction(), HClass::IS_CALLABLE | HClass::IS_BUILTINS_CTOR);
    specificTypedArrayFuncClass->SetConstructor(true);
    env->SetSpecificTypedArrayFunctionClass(thread_, specificTypedArrayFuncClass);

    SetFunctionsGenTypedArrayProto(env, typedArrFuncPrototype);

    SetFunctionsGenTypedArray(env, typedArrayFunction);

    InitializeInt8Array(env, typedArrFuncInstanceDynclass);
    InitializeUint8Array(env, typedArrFuncInstanceDynclass);
    InitializeUint8ClampedArray(env, typedArrFuncInstanceDynclass);
    InitializeInt16Array(env, typedArrFuncInstanceDynclass);
    InitializeUint16Array(env, typedArrFuncInstanceDynclass);
    InitializeInt32Array(env, typedArrFuncInstanceDynclass);
    InitializeUint32Array(env, typedArrFuncInstanceDynclass);
    InitializeFloat32Array(env, typedArrFuncInstanceDynclass);
    InitializeFloat64Array(env, typedArrFuncInstanceDynclass);
    InitializeBigInt64Array(env, typedArrFuncInstanceDynclass);
    InitializeBigUint64Array(env, typedArrFuncInstanceDynclass);
}

void Builtins::InitializeInt8Array(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Int8Array.prototype
    JSHandle<JSObject> int8ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> int8ArrFuncPrototypeValue(int8ArrFuncPrototype);

    // Int8Array.prototype_or_dynclass
    JSHandle<JSHClass> int8ArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_INT8_ARRAY, int8ArrFuncPrototypeValue);

    // Int8Array = new Function()
    JSHandle<JSFunction> int8ArrayFunction =
        factory_->NewSpecificTypedArrayFunction(env, reinterpret_cast<void *>(int8_array::Int8ArrayConstructor));
    InitializeCtor(env, int8ArrFuncPrototype, int8ArrayFunction, "Int8Array", FunctionLength::THREE);

    int8ArrayFunction->SetProtoOrDynClass(thread_, int8ArrFuncInstanceDynclass.GetTaggedValue());

    const int bytesPerElement = 1;
    SetConstant(int8ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    SetConstant(JSHandle<JSObject>(int8ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    env->SetInt8ArrayFunction(thread_, int8ArrayFunction);
}

void Builtins::InitializeUint8Array(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Uint8Array.prototype
    JSHandle<JSObject> uint8ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> uint8ArrFuncPrototypeValue(uint8ArrFuncPrototype);

    // Uint8Array.prototype_or_dynclass
    JSHandle<JSHClass> uint8ArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_UINT8_ARRAY, uint8ArrFuncPrototypeValue);

    // Uint8Array = new Function()
    JSHandle<JSFunction> uint8ArrayFunction =
        factory_->NewSpecificTypedArrayFunction(env, reinterpret_cast<void *>(uint8_array::Uint8ArrayConstructor));
    InitializeCtor(env, uint8ArrFuncPrototype, uint8ArrayFunction, "Uint8Array", FunctionLength::THREE);

    uint8ArrayFunction->SetProtoOrDynClass(thread_, uint8ArrFuncInstanceDynclass.GetTaggedValue());

    const int bytesPerElement = 1;
    SetConstant(uint8ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    SetConstant(JSHandle<JSObject>(uint8ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    env->SetUint8ArrayFunction(thread_, uint8ArrayFunction);
}

void Builtins::InitializeUint8ClampedArray(const JSHandle<GlobalEnv> &env,
                                           const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Uint8ClampedArray.prototype
    JSHandle<JSObject> uint8ClampedArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> uint8ClampedArrFuncPrototypeValue(uint8ClampedArrFuncPrototype);

    // Uint8ClampedArray.prototype_or_dynclass
    JSHandle<JSHClass> uint8ClampedArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_UINT8_CLAMPED_ARRAY, uint8ClampedArrFuncPrototypeValue);

    // Uint8ClampedArray = new Function()
    JSHandle<JSFunction> uint8ClampedArrayFunction = factory_->NewSpecificTypedArrayFunction(
        env, reinterpret_cast<void *>(uint8_clamped_array::Uint8ClampedArrayConstructor));
    InitializeCtor(env, uint8ClampedArrFuncPrototype, uint8ClampedArrayFunction, "Uint8ClampedArray",
                   FunctionLength::THREE);

    uint8ClampedArrayFunction->SetProtoOrDynClass(thread_, uint8ClampedArrFuncInstanceDynclass.GetTaggedValue());

    const int bytesPerElement = 1;
    SetConstant(uint8ClampedArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    SetConstant(JSHandle<JSObject>(uint8ClampedArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    env->SetUint8ClampedArrayFunction(thread_, uint8ClampedArrayFunction);
}

void Builtins::InitializeInt16Array(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Int16Array.prototype
    JSHandle<JSObject> int16ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> int16ArrFuncPrototypeValue(int16ArrFuncPrototype);

    // Int16Array.prototype_or_dynclass
    JSHandle<JSHClass> int16ArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_INT16_ARRAY, int16ArrFuncPrototypeValue);

    // Int16Array = new Function()
    JSHandle<JSFunction> int16ArrayFunction =
        factory_->NewSpecificTypedArrayFunction(env, reinterpret_cast<void *>(int16_array::Int16ArrayConstructor));
    InitializeCtor(env, int16ArrFuncPrototype, int16ArrayFunction, "Int16Array", FunctionLength::THREE);

    int16ArrayFunction->SetProtoOrDynClass(thread_, int16ArrFuncInstanceDynclass.GetTaggedValue());

    const int bytesPerElement = 2;
    SetConstant(int16ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    SetConstant(JSHandle<JSObject>(int16ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    env->SetInt16ArrayFunction(thread_, int16ArrayFunction);
}

void Builtins::InitializeUint16Array(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Uint16Array.prototype
    JSHandle<JSObject> uint16ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> uint16ArrFuncPrototypeValue(uint16ArrFuncPrototype);

    // Uint16Array.prototype_or_dynclass
    JSHandle<JSHClass> uint16ArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_UINT16_ARRAY, uint16ArrFuncPrototypeValue);

    // Uint16Array = new Function()
    JSHandle<JSFunction> uint16ArrayFunction =
        factory_->NewSpecificTypedArrayFunction(env, reinterpret_cast<void *>(uint16_array::Uint16ArrayConstructor));
    InitializeCtor(env, uint16ArrFuncPrototype, uint16ArrayFunction, "Uint16Array", FunctionLength::THREE);

    uint16ArrayFunction->SetProtoOrDynClass(thread_, uint16ArrFuncInstanceDynclass.GetTaggedValue());

    const int bytesPerElement = 2;
    SetConstant(uint16ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    SetConstant(JSHandle<JSObject>(uint16ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    env->SetUint16ArrayFunction(thread_, uint16ArrayFunction);
}

void Builtins::InitializeInt32Array(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Int32Array.prototype
    JSHandle<JSObject> int32ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> int32ArrFuncPrototypeValue(int32ArrFuncPrototype);

    // Int32Array.prototype_or_dynclass
    JSHandle<JSHClass> int32ArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_INT32_ARRAY, int32ArrFuncPrototypeValue);

    // Int32Array = new Function()
    JSHandle<JSFunction> int32ArrayFunction =
        factory_->NewSpecificTypedArrayFunction(env, reinterpret_cast<void *>(int32_array::Int32ArrayConstructor));
    InitializeCtor(env, int32ArrFuncPrototype, int32ArrayFunction, "Int32Array", FunctionLength::THREE);

    int32ArrayFunction->SetProtoOrDynClass(thread_, int32ArrFuncInstanceDynclass.GetTaggedValue());

    const int bytesPerElement = 4;
    SetConstant(int32ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    SetConstant(JSHandle<JSObject>(int32ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    env->SetInt32ArrayFunction(thread_, int32ArrayFunction);
}

void Builtins::InitializeUint32Array(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Uint32Array.prototype
    JSHandle<JSObject> uint32ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> uint32ArrFuncPrototypeValue(uint32ArrFuncPrototype);

    // Uint32Array.prototype_or_dynclass
    JSHandle<JSHClass> uint32ArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_UINT32_ARRAY, uint32ArrFuncPrototypeValue);

    // Uint32Array = new Function()
    JSHandle<JSFunction> uint32ArrayFunction =
        factory_->NewSpecificTypedArrayFunction(env, reinterpret_cast<void *>(uint32_array::Uint32ArrayConstructor));
    InitializeCtor(env, uint32ArrFuncPrototype, uint32ArrayFunction, "Uint32Array", FunctionLength::THREE);

    uint32ArrayFunction->SetProtoOrDynClass(thread_, uint32ArrFuncInstanceDynclass.GetTaggedValue());

    const int bytesPerElement = 4;
    SetConstant(uint32ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    SetConstant(JSHandle<JSObject>(uint32ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    env->SetUint32ArrayFunction(thread_, uint32ArrayFunction);
}

void Builtins::InitializeFloat32Array(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Float32Array.prototype
    JSHandle<JSObject> float32ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> float32ArrFuncPrototypeValue(float32ArrFuncPrototype);

    // Float32Array.prototype_or_dynclass
    JSHandle<JSHClass> float32ArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_FLOAT32_ARRAY, float32ArrFuncPrototypeValue);

    // Float32Array = new Function()
    JSHandle<JSFunction> float32ArrayFunction =
        factory_->NewSpecificTypedArrayFunction(env, reinterpret_cast<void *>(float32_array::Float32ArrayConstructor));
    InitializeCtor(env, float32ArrFuncPrototype, float32ArrayFunction, "Float32Array", FunctionLength::THREE);

    float32ArrayFunction->SetProtoOrDynClass(thread_, float32ArrFuncInstanceDynclass.GetTaggedValue());

    const int bytesPerElement = 4;
    SetConstant(float32ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    SetConstant(JSHandle<JSObject>(float32ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    env->SetFloat32ArrayFunction(thread_, float32ArrayFunction);
}

void Builtins::InitializeFloat64Array(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Float64Array.prototype
    JSHandle<JSObject> float64ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> float64ArrFuncPrototypeValue(float64ArrFuncPrototype);

    // Float64Array.prototype_or_dynclass
    JSHandle<JSHClass> float64ArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_FLOAT64_ARRAY, float64ArrFuncPrototypeValue);

    // Float64Array = new Function()
    JSHandle<JSFunction> float64ArrayFunction =
        factory_->NewSpecificTypedArrayFunction(env, reinterpret_cast<void *>(float64_array::Float64ArrayConstructor));
    InitializeCtor(env, float64ArrFuncPrototype, float64ArrayFunction, "Float64Array", FunctionLength::THREE);

    float64ArrayFunction->SetProtoOrDynClass(thread_, float64ArrFuncInstanceDynclass.GetTaggedValue());

    const int bytesPerElement = 8;
    SetConstant(float64ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    SetConstant(JSHandle<JSObject>(float64ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    env->SetFloat64ArrayFunction(thread_, float64ArrayFunction);
}

void Builtins::InitializeBigInt64Array(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // BigInt64Array.prototype
    JSHandle<JSObject> bigInt64ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> bigInt64ArrFuncPrototypeValue(bigInt64ArrFuncPrototype);

    // BigInt64Array.prototype_or_dynclass
    JSHandle<JSHClass> bigInt64ArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_BIGINT64_ARRAY, bigInt64ArrFuncPrototypeValue);

    // BigInt64Array = new Function()
    JSHandle<JSFunction> bigInt64ArrayFunction = factory_->NewSpecificTypedArrayFunction(
        env, reinterpret_cast<void *>(big_int64_array::BigInt64ArrayConstructor));
    InitializeCtor(env, bigInt64ArrFuncPrototype, bigInt64ArrayFunction, "BigInt64Array", FunctionLength::THREE);

    bigInt64ArrayFunction->SetProtoOrDynClass(thread_, bigInt64ArrFuncInstanceDynclass.GetTaggedValue());

    const int bytesPerElement = 8;
    SetConstant(bigInt64ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    SetConstant(JSHandle<JSObject>(bigInt64ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    env->SetBigInt64ArrayFunction(thread_, bigInt64ArrayFunction);
}

void Builtins::InitializeBigUint64Array(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // BigUint64Array.prototype
    JSHandle<JSObject> bigUint64ArrFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> bigUint64ArrFuncPrototypeValue(bigUint64ArrFuncPrototype);

    // BigUint64Array.prototype_or_dynclass
    JSHandle<JSHClass> bigUint64ArrFuncInstanceDynclass =
        factory_->CreateDynClass<JSTypedArray>(JSType::JS_BIGUINT64_ARRAY, bigUint64ArrFuncPrototypeValue);

    // BigUint64Array = new Function()
    JSHandle<JSFunction> bigUint64ArrayFunction = factory_->NewSpecificTypedArrayFunction(
        env, reinterpret_cast<void *>(big_uint64_array::BigUint64ArrayConstructor));
    InitializeCtor(env, bigUint64ArrFuncPrototype, bigUint64ArrayFunction, "BigUint64Array", FunctionLength::THREE);

    bigUint64ArrayFunction->SetProtoOrDynClass(thread_, bigUint64ArrFuncInstanceDynclass.GetTaggedValue());

    const int bytesPerElement = 8;
    SetConstant(bigUint64ArrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    SetConstant(JSHandle<JSObject>(bigUint64ArrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement));
    env->SetBigUint64ArrayFunction(thread_, bigUint64ArrayFunction);
}

void Builtins::InitializeArrayBuffer(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // ArrayBuffer.prototype
    JSHandle<JSObject> arrayBufferFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> arrayBufferFuncPrototypeValue(arrayBufferFuncPrototype);

    //  ArrayBuffer.prototype_or_dynclass
    JSHandle<JSHClass> arrayBufferFuncInstanceDynclass =
        factory_->CreateDynClass<JSArrayBuffer>(JSType::JS_ARRAY_BUFFER, arrayBufferFuncPrototypeValue);

    // ArrayBuffer = new Function()
    JSHandle<JSObject> arrayBufferFunction(NewBuiltinConstructor(env, arrayBufferFuncPrototype,
                                                                 builtins::array_buffer::ArrayBufferConstructor,
                                                                 "ArrayBuffer", FunctionLength::ONE));

    JSHandle<JSFunction>(arrayBufferFunction)
        ->SetFunctionPrototype(thread_, arrayBufferFuncInstanceDynclass.GetTaggedValue());

    SetFunctionsGenArrayBufferProto(env, arrayBufferFuncPrototype);
    SetFunctionsGenArrayBuffer(env, arrayBufferFunction);

    // 24.1.4.4 ArrayBuffer.prototype[@@toStringTag]
    SetStringTagSymbol(env, arrayBufferFuncPrototype, "ArrayBuffer");

    env->SetArrayBufferFunction(thread_, arrayBufferFunction.GetTaggedValue());
}

void Builtins::InitializeReflect(const JSHandle<GlobalEnv> &env,
                                 const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    JSHandle<JSHClass> reflectDynclass = factory_->CreateDynClass<JSObject>(JSType::JS_OBJECT, objFuncPrototypeVal);
    JSHandle<JSObject> reflectObject = factory_->NewJSObject(reflectDynclass);

    SetFunctionsGenReflect(env, reflectObject);

    JSHandle<JSTaggedValue> reflectString(factory_->NewFromCanBeCompressString("Reflect"));
    JSHandle<JSObject> globalObject(thread_, env->GetGlobalObject());
    PropertyDescriptor reflectDesc(thread_, JSHandle<JSTaggedValue>::Cast(reflectObject), true, false, true);
    JSObject::DefineOwnProperty(thread_, globalObject, reflectString, reflectDesc);

    // @@ToStringTag
    SetStringTagSymbol(env, reflectObject, "Reflect");

    env->SetReflectFunction(thread_, reflectObject.GetTaggedValue());
}

void Builtins::InitializePromise(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &promiseFuncDynclass)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Promise.prototype
    JSHandle<JSObject> promiseFuncPrototype = factory_->NewJSObject(promiseFuncDynclass);
    JSHandle<JSTaggedValue> promiseFuncPrototypeValue(promiseFuncPrototype);
    // Promise.prototype_or_dynclass
    JSHandle<JSHClass> promiseFuncInstanceDynclass =
        factory_->CreateDynClass<JSPromise>(JSType::JS_PROMISE, promiseFuncPrototypeValue);
    // Promise() = new Function()
    JSHandle<JSObject> promiseFunction(
        NewBuiltinConstructor(env, promiseFuncPrototype, promise::PromiseConstructor, "Promise", FunctionLength::ONE));
    JSHandle<JSFunction>(promiseFunction)->SetFunctionPrototype(thread_, promiseFuncInstanceDynclass.GetTaggedValue());
    SetFunctionsGenPromise(env, promiseFunction);

    SetFunctionsGenPromiseProto(env, promiseFuncPrototype);

    // Promise.prototype [ @@toStringTag ]
    SetStringTagSymbol(env, promiseFuncPrototype, "Promise");

    env->SetPromiseFunction(thread_, promiseFunction);
}

void Builtins::InitializePromiseJob(const JSHandle<GlobalEnv> &env)
{
    JSHandle<JSTaggedValue> keyString(thread_->GlobalConstants()->GetHandledEmptyString());
    auto func = NewFunction(env, keyString, promise_job::PromiseReactionJob, FunctionLength::TWO);
    env->SetPromiseReactionJob(thread_, func);
    func = NewFunction(env, keyString, promise_job::PromiseResolveThenableJob, FunctionLength::THREE);
    env->SetPromiseResolveThenableJob(thread_, func);
}

void Builtins::InitializeFinalizationRegistry(const JSHandle<GlobalEnv> &env,
                                              const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    // FinalizationRegistry.prototype
    JSHandle<JSObject> registryFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> registryFuncPrototypeValue(registryFuncPrototype);
    // FinalizationRegistry.prototype_or_dynclass
    JSHandle<JSHClass> registryFuncInstanceDynclass =
        factory_->CreateDynClass<JSFinalizationRegistry>(JSType::FINALIZATION_REGISTRY, registryFuncPrototypeValue);
    // FinalizationRegistry() = new Function()
    JSHandle<JSTaggedValue> registryFunction(NewBuiltinConstructor(
        env, registryFuncPrototype, finalization_registry::Constructor, "FinalizationRegistry", FunctionLength::ONE));
    // FinalizationRegistry().prototype = FinalizationRegistry.Prototype &
    // FinalizationRegistry.prototype.constructor = Finalizationregistry()
    JSFunction::Cast(registryFunction->GetTaggedObject())
        ->SetProtoOrDynClass(thread_, registryFuncInstanceDynclass.GetTaggedValue());

    // "constructor" property on the prototype
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    JSObject::SetProperty(thread_, JSHandle<JSTaggedValue>(registryFuncPrototype), constructorKey, registryFunction);

    SetFunctionsGenFinalizationRegistryProto(env, registryFuncPrototype);
    // @@ToStringTag
    SetStringTagSymbol(env, registryFuncPrototype, "FinalizationRegistry");

    const_cast<GlobalEnvConstants *>(globalConst)
        ->SetConstant(ConstantIndex::FINALIZATION_REGISTRY_CLASS_INDEX, registryFuncInstanceDynclass.GetTaggedValue());
}

void Builtins::InitializeDataView(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // ArrayBuffer.prototype
    JSHandle<JSObject> dataViewFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> dataViewFuncPrototypeValue(dataViewFuncPrototype);

    //  ArrayBuffer.prototype_or_dynclass
    JSHandle<JSHClass> dataViewFuncInstanceDynclass =
        factory_->CreateDynClass<JSDataView>(JSType::JS_DATA_VIEW, dataViewFuncPrototypeValue);

    // ArrayBuffer = new Function()
    JSHandle<JSObject> dataViewFunction(NewBuiltinConstructor(
        env, dataViewFuncPrototype, data_view::DataViewConstructor, "DataView", FunctionLength::ONE));

    JSHandle<JSFunction>(dataViewFunction)->SetProtoOrDynClass(thread_, dataViewFuncInstanceDynclass.GetTaggedValue());

    SetFunctionsGenDataViewProto(env, dataViewFuncPrototype);

    // 24.2.4.21 DataView.prototype[ @@toStringTag ]
    SetStringTagSymbol(env, dataViewFuncPrototype, "DataView");
    env->SetDataViewFunction(thread_, dataViewFunction.GetTaggedValue());
}

JSHandle<JSFunction> Builtins::NewBuiltinConstructor(const JSHandle<GlobalEnv> &env,
                                                     const JSHandle<JSObject> &prototype, EcmaEntrypoint ctorFunc,
                                                     const char *name, int length) const
{
    JSHandle<JSFunction> ctor =
        factory_->NewJSFunction(env, reinterpret_cast<void *>(ctorFunc), FunctionKind::BUILTIN_CONSTRUCTOR);
    InitializeCtor(env, prototype, ctor, name, length);
    return ctor;
}

JSHandle<JSFunction> Builtins::NewFunction(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &key,
                                           EcmaEntrypoint func, int length) const
{
    JSHandle<JSFunction> function = factory_->NewJSFunction(env, reinterpret_cast<void *>(func));
    JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(length));
    JSHandle<JSFunctionBase> baseFunction(function);
    JSHandle<JSTaggedValue> handleUndefine(thread_, JSTaggedValue::Undefined());
    JSFunction::SetFunctionName(thread_, baseFunction, key, handleUndefine);
    return function;
}

void Builtins::SetFunction(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &obj, const char *key,
                           EcmaEntrypoint func, int length) const
{
    JSHandle<JSTaggedValue> keyString(factory_->NewFromString(key));
    SetFunction(env, obj, keyString, func, length);
}

void Builtins::SetFunction(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &obj,
                           const JSHandle<JSTaggedValue> &key, EcmaEntrypoint func, int length) const
{
    JSHandle<JSFunction> function(NewFunction(env, key, func, length));
    SetFunction(obj, key, JSHandle<JSTaggedValue>(function));
}

void Builtins::SetFunction(const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
                           const JSHandle<JSTaggedValue> &func) const
{
    PropertyDescriptor descriptor(thread_, func, true, false, true);
    JSObject::DefineOwnProperty(thread_, obj, key, descriptor);
}

void Builtins::SetFrozenFunction(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &obj, const char *key,
                                 EcmaEntrypoint func, int length) const
{
    JSHandle<JSTaggedValue> keyString(factory_->NewFromString(key));
    JSHandle<JSFunction> function = NewFunction(env, keyString, func, length);
    PropertyDescriptor descriptor(thread_, JSHandle<JSTaggedValue>(function), false, false, false);
    JSObject::DefineOwnProperty(thread_, obj, keyString, descriptor);
}

template <JSSymbol::SymbolType FLAG>
void Builtins::SetFunctionAtSymbol(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &obj,
                                   const JSHandle<JSTaggedValue> &symbol, const char *name, EcmaEntrypoint func,
                                   int length) const
{
    JSHandle<JSFunction> function = factory_->NewJSFunction(env, reinterpret_cast<void *>(func));
    JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(length));
    JSHandle<JSTaggedValue> nameString(factory_->NewFromString(name));
    JSHandle<JSFunctionBase> baseFunction(function);
    JSHandle<JSTaggedValue> handleUndefine(thread_, JSTaggedValue::Undefined());
    JSFunction::SetFunctionName(thread_, baseFunction, nameString, handleUndefine);
    SetFunctionAtSymbol<FLAG>(obj, symbol, JSHandle<JSTaggedValue>::Cast(function));
}

template <JSSymbol::SymbolType FLAG>
void Builtins::SetFunctionAtSymbol(const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &symbol,
                                   const JSHandle<JSTaggedValue> &function) const
{
    // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
    if constexpr (FLAG == JSSymbol::SymbolType::TO_PRIMITIVE) {
        PropertyDescriptor descriptor(thread_, function, false, false, true);
        JSObject::DefineOwnProperty(thread_, obj, symbol, descriptor);
        return;
    }
    if constexpr (FLAG == JSSymbol::SymbolType::HAS_INSTANCE) {  // NOLINTE(readability-braces-around-statements)
        // ecma 19.2.3.6 Function.prototype[@@hasInstance] has the attributes
        // { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.
        PropertyDescriptor descriptor(thread_, function, false, false, false);
        JSObject::DefineOwnProperty(thread_, obj, symbol, descriptor);
        return;
    }
    PropertyDescriptor descriptor(thread_, function, true, false, true);
    JSObject::DefineOwnProperty(thread_, obj, symbol, descriptor);
}

void Builtins::SetStringTagSymbol(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &obj, const char *key) const
{
    JSHandle<JSTaggedValue> tag(factory_->NewFromString(key));
    JSHandle<JSTaggedValue> symbol = env->GetToStringTagSymbol();
    PropertyDescriptor desc(thread_, tag, false, false, true);
    JSObject::DefineOwnProperty(thread_, obj, symbol, desc);
}

JSHandle<JSTaggedValue> Builtins::CreateGetter(const JSHandle<GlobalEnv> &env, EcmaEntrypoint func, const char *name,
                                               int length) const
{
    ASSERT(length == 0);
    JSHandle<JSFunction> function = factory_->NewJSFunction(env, reinterpret_cast<void *>(func));
    JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(length));
    JSHandle<JSTaggedValue> funcName(factory_->NewFromString(name));
    JSHandle<JSTaggedValue> prefix = thread_->GlobalConstants()->GetHandledGetString();
    JSFunction::SetFunctionName(thread_, JSHandle<JSFunctionBase>(function), funcName, prefix);
    return JSHandle<JSTaggedValue>(function);
}

JSHandle<JSTaggedValue> Builtins::CreateSetter(const JSHandle<GlobalEnv> &env, EcmaEntrypoint func, const char *name,
                                               int length) const
{
    ASSERT(length == 1);
    JSHandle<JSFunction> function = factory_->NewJSFunction(env, reinterpret_cast<void *>(func));
    JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(length));
    JSHandle<JSTaggedValue> funcName(factory_->NewFromString(name));
    JSHandle<JSTaggedValue> prefix = thread_->GlobalConstants()->GetHandledSetString();
    JSFunction::SetFunctionName(thread_, JSHandle<JSFunctionBase>(function), funcName, prefix);
    return JSHandle<JSTaggedValue>(function);
}

void Builtins::SetConstant(const JSHandle<JSObject> &obj, const char *key, JSTaggedValue value) const
{
    JSHandle<JSTaggedValue> valueHandle(thread_, value);
    JSHandle<JSTaggedValue> keyString(factory_->NewFromString(key));
    PropertyDescriptor descriptor(thread_, valueHandle, false, false, false);
    JSObject::DefineOwnProperty(thread_, obj, keyString, descriptor);
}

void Builtins::SetConstantObject(const JSHandle<JSObject> &obj, const char *key, JSHandle<JSTaggedValue> &value) const
{
    JSHandle<JSTaggedValue> keyString(factory_->NewFromString(key));
    PropertyDescriptor descriptor(thread_, value, false, false, false);
    JSObject::DefineOwnProperty(thread_, obj, keyString, descriptor);
}

void Builtins::SetGlobalThis(const JSHandle<JSObject> &obj, const char *key, const JSHandle<JSTaggedValue> &globalValue)
{
    JSHandle<JSTaggedValue> keyString(factory_->NewFromString(key));
    PropertyDescriptor descriptor(thread_, globalValue, true, false, true);
    JSObject::DefineOwnProperty(thread_, obj, keyString, descriptor);
}

void Builtins::SetAttribute(const JSHandle<JSObject> &obj, const char *key, const char *value) const
{
    JSHandle<JSTaggedValue> keyString(factory_->NewFromString(key));
    PropertyDescriptor descriptor(thread_, JSHandle<JSTaggedValue>(factory_->NewFromString(value)), true, false, true);
    JSObject::DefineOwnProperty(thread_, obj, keyString, descriptor);
}

void Builtins::SetNoneAttributeProperty(const JSHandle<JSObject> &obj, const char *key,
                                        const JSHandle<JSTaggedValue> &value) const
{
    JSHandle<JSTaggedValue> keyString(factory_->NewFromString(key));
    PropertyDescriptor des(thread_, value, false, false, false);
    JSObject::DefineOwnProperty(thread_, obj, keyString, des);
}

void Builtins::StrictModeForbiddenAccessCallerArguments(const JSHandle<GlobalEnv> &env,
                                                        const JSHandle<JSObject> &prototype) const
{
    JSHandle<JSFunction> function =
        factory_->NewJSFunction(env, reinterpret_cast<void *>(JSFunction::AccessCallerArgumentsThrowTypeError));

    JSHandle<JSTaggedValue> caller(factory_->NewFromCanBeCompressString("caller"));
    SetAccessor(prototype, caller, JSHandle<JSTaggedValue>::Cast(function), JSHandle<JSTaggedValue>::Cast(function));

    JSHandle<JSTaggedValue> arguments(factory_->NewFromCanBeCompressString("arguments"));
    SetAccessor(prototype, arguments, JSHandle<JSTaggedValue>::Cast(function), JSHandle<JSTaggedValue>::Cast(function));
}

void Builtins::InitializeGeneratorFunction(const JSHandle<GlobalEnv> &env,
                                           const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    JSHandle<JSObject> generatorFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> generatorFuncPrototypeValue(generatorFuncPrototype);

    // 26.3.3.1 GeneratorFunction.prototype.constructor
    // GeneratorFunction.prototype_or_dynclass
    JSHandle<JSHClass> generatorFuncInstanceDynclass = factory_->CreateDynClass<JSFunction>(
        JSType::JS_GENERATOR_FUNCTION, generatorFuncPrototypeValue, HClass::IS_CALLABLE);
    generatorFuncInstanceDynclass->SetExtensible(true);
    // GeneratorFunction = new GeneratorFunction()
    JSHandle<JSFunction> generatorFunction =
        NewBuiltinConstructor(env, generatorFuncPrototype, builtins::generator_function::GeneratorFunctionConstructor,
                              "GeneratorFunction", FunctionLength::ONE);
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    PropertyDescriptor generatorDesc(thread_, JSHandle<JSTaggedValue>::Cast(generatorFunction), false, false, true);
    JSObject::DefineOwnProperty(thread_, generatorFuncPrototype, constructorKey, generatorDesc);
    generatorFunction->SetProtoOrDynClass(thread_, generatorFuncInstanceDynclass.GetTaggedValue());
    env->SetGeneratorFunctionFunction(thread_, generatorFunction);

    // 26.3.3.2 GeneratorFunction.prototype.prototype -> Generator prototype object.
    PropertyDescriptor descriptor(thread_, env->GetGeneratorPrototype(), false, false, true);
    JSObject::DefineOwnProperty(thread_, generatorFuncPrototype, globalConst->GetHandledPrototypeString(), descriptor);

    // 26.3.3.3 GeneratorFunction.prototype[@@toStringTag]
    SetStringTagSymbol(env, generatorFuncPrototype, "GeneratorFunction");

    // GeneratorFunction prototype __proto__ -> Function.
    JSObject::SetPrototype(thread_, generatorFuncPrototype, env->GetFunctionPrototype());

    // 26.5.1.1 Generator.prototype.constructor -> %GeneratorFunction.prototype%.
    PropertyDescriptor generatorObjDesc(thread_, generatorFuncPrototypeValue, false, false, true);
    JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>(env->GetInitialGenerator()),
                                globalConst->GetHandledConstructorString(), generatorObjDesc);

    // Generator instances prototype -> GeneratorFunction.prototype.prototype
    PropertyDescriptor generatorObjProtoDesc(thread_, generatorFuncPrototypeValue, true, false, false);
    JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>(env->GetInitialGenerator()),
                                globalConst->GetHandledPrototypeString(), generatorObjProtoDesc);

    env->SetGeneratorFunctionPrototype(thread_, generatorFuncPrototype);
}

void Builtins::InitializeGenerator(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    JSHandle<JSObject> generatorFuncPrototype = factory_->NewJSObject(objFuncDynclass);

    SetFunctionsGenGeneratorProto(env, generatorFuncPrototype);

    // 26.5.1.5 Generator.prototype[@@toStringTag]
    SetStringTagSymbol(env, generatorFuncPrototype, "Generator");

    // Generator with constructor, symbolTag, next/return/throw etc.
    PropertyDescriptor descriptor(thread_, env->GetIteratorPrototype(), true, false, false);
    JSObject::DefineOwnProperty(thread_, generatorFuncPrototype, globalConst->GetHandledPrototypeString(), descriptor);
    env->SetGeneratorPrototype(thread_, generatorFuncPrototype);
    JSObject::SetPrototype(thread_, generatorFuncPrototype, env->GetIteratorPrototype());

    // Generator {}
    JSHandle<JSObject> initialGeneratorFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSObject::SetPrototype(thread_, initialGeneratorFuncPrototype, JSHandle<JSTaggedValue>(generatorFuncPrototype));
    env->SetInitialGenerator(thread_, initialGeneratorFuncPrototype);
}

void Builtins::InitializeAsyncGeneratorFunction(const JSHandle<GlobalEnv> &env,
                                                const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    JSHandle<JSObject> asyncGeneratorFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> asyncGeneratorFuncPrototypeValue(asyncGeneratorFuncPrototype);

    // 26.3.3.1 AsyncGeneratorFunction.prototype.constructor
    // AsyncGeneratorFunction.prototype_or_dynclass
    JSHandle<JSHClass> asyncGeneratorFuncInstanceDynclass = factory_->CreateDynClass<JSFunction>(
        JSType::JS_ASYNC_GENERATOR_FUNCTION, asyncGeneratorFuncPrototypeValue, HClass::IS_CALLABLE);
    asyncGeneratorFuncInstanceDynclass->SetExtensible(true);

    // AsyncGeneratorFunction = new AsyncGeneratorFunction()
    JSHandle<JSFunction> asyncGeneratorFunction = NewBuiltinConstructor(
        env, asyncGeneratorFuncPrototype, builtins::async_generator_function::AsyncGeneratorFunctionConstructor,
        "AsyncGeneratorFunction", FunctionLength::ONE);
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    PropertyDescriptor asyncGeneratorDesc(thread_, JSHandle<JSTaggedValue>::Cast(asyncGeneratorFunction), false, false,
                                          true);
    JSObject::DefineOwnProperty(thread_, asyncGeneratorFuncPrototype, constructorKey, asyncGeneratorDesc);
    asyncGeneratorFunction->SetProtoOrDynClass(thread_, asyncGeneratorFuncInstanceDynclass.GetTaggedValue());
    env->SetAsyncGeneratorFunctionFunction(thread_, asyncGeneratorFunction);

    // 26.3.3.2 AsyncGeneratorFunction.prototype.prototype -> AsyncGenerator prototype object.
    PropertyDescriptor descriptor(thread_, env->GetAsyncGeneratorPrototype(), false, false, true);
    JSObject::DefineOwnProperty(thread_, asyncGeneratorFuncPrototype, globalConst->GetHandledPrototypeString(),
                                descriptor);

    // 26.3.3.3 AsyncGeneratorFunction.prototype[@@toStringTag]
    SetStringTagSymbol(env, asyncGeneratorFuncPrototype, "AsyncGeneratorFunction");

    // AsyncGeneratorFunction prototype __proto__ -> Function.
    JSObject::SetPrototype(thread_, asyncGeneratorFuncPrototype, env->GetFunctionPrototype());

    // 26.5.1.1 AsyncGenerator.prototype.constructor -> %AsyncGeneratorFunction.prototype%.
    PropertyDescriptor asyncGeneratorObjDesc(thread_, asyncGeneratorFuncPrototypeValue, false, false, true);
    JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>(env->GetInitialAsyncGenerator()),
                                globalConst->GetHandledConstructorString(), asyncGeneratorObjDesc);

    // AsyncGenerator instances prototype -> AsyncGeneratorFunction.prototype.prototype
    PropertyDescriptor asyncGeneratorObjProtoDesc(thread_, asyncGeneratorFuncPrototypeValue, true, false, false);
    JSObject::DefineOwnProperty(thread_, JSHandle<JSObject>(env->GetInitialAsyncGenerator()),
                                globalConst->GetHandledPrototypeString(), asyncGeneratorObjProtoDesc);

    env->SetAsyncGeneratorFunctionPrototype(thread_, asyncGeneratorFuncPrototype);
}

void Builtins::InitializeAsyncGenerator(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    JSHandle<JSObject> asyncGeneratorFuncPrototype = factory_->NewJSObject(objFuncDynclass);

    SetFunctionsGenAsyncGeneratorProto(env, asyncGeneratorFuncPrototype);

    // 27.6.1.5 AsyncGenerator.prototype[@@toStringTag]
    SetStringTagSymbol(env, asyncGeneratorFuncPrototype, "AsyncGenerator");

    PropertyDescriptor descriptor(thread_, env->GetAsyncIteratorPrototype(), true, false, false);
    JSObject::DefineOwnProperty(thread_, asyncGeneratorFuncPrototype, globalConst->GetHandledPrototypeString(),
                                descriptor);
    env->SetAsyncGeneratorPrototype(thread_, asyncGeneratorFuncPrototype);
    JSObject::SetPrototype(thread_, asyncGeneratorFuncPrototype, env->GetAsyncIteratorPrototype());

    // AsyncGenerator {}
    JSHandle<JSObject> initialAsyncGeneratorFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSObject::SetPrototype(thread_, initialAsyncGeneratorFuncPrototype,
                           JSHandle<JSTaggedValue>(asyncGeneratorFuncPrototype));
    env->SetInitialAsyncGenerator(thread_, initialAsyncGeneratorFuncPrototype);
}

void Builtins::InitializeAsyncFromSyncIteratorPrototypeObject(const JSHandle<GlobalEnv> &env,
                                                              const JSHandle<JSHClass> &objFuncDynclass) const
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    JSHandle<JSObject> asyncFromSyncIteratorPrototype = factory_->NewJSObject(objFuncDynclass);

    SetFunctionsGenAsyncFromSyncIteratorProto(env, asyncFromSyncIteratorPrototype);

    JSObject::SetPrototype(thread_, asyncFromSyncIteratorPrototype, env->GetAsyncIteratorPrototype());
    env->SetAsyncFromSyncIteratorPrototype(thread_, asyncFromSyncIteratorPrototype);
}

void Builtins::SetArgumentsSharedAccessor(const JSHandle<GlobalEnv> &env)
{
    JSHandle<JSTaggedValue> throwFunction = env->GetThrowTypeError();

    JSHandle<AccessorData> accessor = factory_->NewAccessorData();
    accessor->SetGetter(thread_, throwFunction);
    accessor->SetSetter(thread_, throwFunction);
    env->SetArgumentsCallerAccessor(thread_, accessor);

    accessor = factory_->NewAccessorData();
    accessor->SetGetter(thread_, throwFunction);
    accessor->SetSetter(thread_, throwFunction);
    env->SetArgumentsCalleeAccessor(thread_, accessor);
}

void Builtins::SetAccessor(const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
                           const JSHandle<JSTaggedValue> &getter, const JSHandle<JSTaggedValue> &setter) const
{
    JSHandle<AccessorData> accessor = factory_->NewAccessorData();
    accessor->SetGetter(thread_, getter);
    accessor->SetSetter(thread_, setter);
    PropertyAttributes attr = PropertyAttributes::DefaultAccessor(false, false, true);
    JSObject::AddAccessor(thread_, JSHandle<JSTaggedValue>::Cast(obj), key, accessor, attr);
}

void Builtins::SetGetter(const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &key,
                         const JSHandle<JSTaggedValue> &getter) const
{
    JSHandle<AccessorData> accessor = factory_->NewAccessorData();
    accessor->SetGetter(thread_, getter);
    PropertyAttributes attr = PropertyAttributes::DefaultAccessor(false, false, true);
    JSObject::AddAccessor(thread_, JSHandle<JSTaggedValue>::Cast(obj), key, accessor, attr);
}

JSHandle<JSFunction> Builtins::NewIntlConstructor(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &prototype,
                                                  EcmaEntrypoint ctorFunc, const char *name, int length)
{
    JSHandle<JSFunction> ctor =
        factory_->NewJSFunction(env, reinterpret_cast<void *>(ctorFunc), FunctionKind::BUILTIN_CONSTRUCTOR);
    InitializeIntlCtor(env, prototype, ctor, name, length);
    return ctor;
}

void Builtins::InitializeIntlCtor(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &prototype,
                                  const JSHandle<JSFunction> &ctor, const char *name, int length)
{
    const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
    JSFunction::SetFunctionLength(thread_, ctor, JSTaggedValue(length));
    JSHandle<JSTaggedValue> nameString(factory_->NewFromString(name));
    JSFunction::SetFunctionName(thread_, JSHandle<JSFunctionBase>(ctor), nameString,
                                JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()));
    JSHandle<JSTaggedValue> constructorKey = globalConst->GetHandledConstructorString();
    PropertyDescriptor descriptor1(thread_, JSHandle<JSTaggedValue>::Cast(ctor), true, false, true);
    JSObject::DefineOwnProperty(thread_, prototype, constructorKey, descriptor1);

    // set "prototype" in constructor.
    ctor->SetFunctionPrototype(thread_, prototype.GetTaggedValue());

    if (!JSTaggedValue::SameValue(nameString, thread_->GlobalConstants()->GetHandledAsyncFunctionString())) {
        JSHandle<JSObject> intlObject(thread_, env->GetIntlFunction().GetTaggedValue());
        PropertyDescriptor descriptor2(thread_, JSHandle<JSTaggedValue>::Cast(ctor), true, false, true);
        JSObject::DefineOwnProperty(thread_, intlObject, nameString, descriptor2);
    }
}

void Builtins::InitializeIntl(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeValue)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    JSHandle<JSHClass> intlDynclass = factory_->CreateDynClass<JSObject>(JSType::JS_INTL, objFuncPrototypeValue);
    JSHandle<JSObject> intlObject = factory_->NewJSObject(intlDynclass);

    JSHandle<JSTaggedValue> initIntlSymbol(factory_->NewPublicSymbolWithChar("Symbol.IntlLegacyConstructedSymbol"));
    SetNoneAttributeProperty(intlObject, "fallbackSymbol", initIntlSymbol);

    SetFunctionsGenIntl(env, intlObject);

    // initial value of the "Intl" property of the global object.
    JSHandle<JSTaggedValue> intlString(factory_->NewFromString("Intl"));
    JSHandle<JSObject> globalObject(thread_, env->GetGlobalObject());
    PropertyDescriptor intlDesc(thread_, JSHandle<JSTaggedValue>::Cast(intlObject), true, false, true);
    JSObject::DefineOwnProperty(thread_, globalObject, intlString, intlDesc);

    SetStringTagSymbol(env, intlObject, "Intl");

    env->SetIntlFunction(thread_, intlObject);
}

void Builtins::InitializeDateTimeFormat(const JSHandle<GlobalEnv> &env)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // DateTimeFormat.prototype
    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
    JSHandle<JSObject> dtfPrototype = factory_->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
    JSHandle<JSTaggedValue> dtfPrototypeValue(dtfPrototype);

    // DateTimeFormat.prototype_or_dynclass
    JSHandle<JSHClass> dtfFuncInstanceDynclass =
        factory_->CreateDynClass<JSDateTimeFormat>(JSType::JS_DATE_TIME_FORMAT, dtfPrototypeValue);

    // DateTimeFormat = new Function()
    // 13.4.1 Intl.DateTimeFormat.prototype.constructor
    JSHandle<JSObject> dtfFunction(NewIntlConstructor(env, dtfPrototype, date_time_format::DateTimeFormatConstructor,
                                                      "DateTimeFormat", FunctionLength::ZERO));
    JSHandle<JSFunction>(dtfFunction)->SetFunctionPrototype(thread_, JSTaggedValue(*dtfFuncInstanceDynclass));

    SetFunctionsGenDateTimeFormat(env, dtfFunction);

    // DateTimeFormat.prototype method
    // 13.4.2 Intl.DateTimeFormat.prototype [ @@toStringTag ]
    SetStringTagSymbol(env, dtfPrototype, "Intl.DateTimeFormat");
    env->SetDateTimeFormatFunction(thread_, dtfFunction);

    SetFunctionsGenDateTimeFormatProto(env, dtfPrototype);
}

void Builtins::InitializeRelativeTimeFormat(const JSHandle<GlobalEnv> &env)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // RelativeTimeFormat.prototype
    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
    JSHandle<JSObject> rtfPrototype = factory_->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
    JSHandle<JSTaggedValue> rtfPrototypeValue(rtfPrototype);

    // RelativeTimeFormat.prototype_or_dynclass
    JSHandle<JSHClass> rtfFuncInstanceDynclass =
        factory_->CreateDynClass<JSRelativeTimeFormat>(JSType::JS_RELATIVE_TIME_FORMAT, rtfPrototypeValue);

    // RelativeTimeFormat = new Function()
    // 14.2.1 Intl.RelativeTimeFormat.prototype.constructor
    JSHandle<JSObject> rtfFunction(NewIntlConstructor(env, rtfPrototype,
                                                      relative_time_format::RelativeTimeFormatConstructor,
                                                      "RelativeTimeFormat", FunctionLength::ZERO));
    JSHandle<JSFunction>(rtfFunction)->SetFunctionPrototype(thread_, JSTaggedValue(*rtfFuncInstanceDynclass));
    SetFunctionsGenRelativeTimeFormat(env, rtfFunction);

    // RelativeTimeFormat.prototype method
    // 14.4.2 Intl.RelativeTimeFormat.prototype [ @@toStringTag ]
    SetStringTagSymbol(env, rtfPrototype, "Intl.RelativeTimeFormat");
    env->SetRelativeTimeFormatFunction(thread_, rtfFunction);

    SetFunctionsGenRelativeTimeFormatProto(env, rtfPrototype);
}

void Builtins::InitializeNumberFormat(const JSHandle<GlobalEnv> &env)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // NumberFormat.prototype
    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
    JSHandle<JSObject> nfPrototype = factory_->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
    JSHandle<JSTaggedValue> nfPrototypeValue(nfPrototype);

    // NumberFormat.prototype_or_dynclass
    JSHandle<JSHClass> nfFuncInstanceDynclass =
        factory_->CreateDynClass<JSNumberFormat>(JSType::JS_NUMBER_FORMAT, nfPrototypeValue);

    // NumberFormat = new Function()
    // 12.4.1 Intl.NumberFormat.prototype.constructor
    JSHandle<JSObject> nfFunction(NewIntlConstructor(env, nfPrototype, number_format::NumberFormatConstructor,
                                                     "NumberFormat", FunctionLength::ZERO));
    JSHandle<JSFunction>(nfFunction)->SetFunctionPrototype(thread_, JSTaggedValue(*nfFuncInstanceDynclass));

    SetFunctionsGenNumberFormat(env, nfFunction);
    // NumberFormat.prototype method
    // 12.4.2 Intl.NumberFormat.prototype [ @@toStringTag ]
    SetStringTagSymbol(env, nfPrototype, "Intl.NumberFormat");
    env->SetNumberFormatFunction(thread_, nfFunction);

    SetFunctionsGenNumberFormatProto(env, nfPrototype);
}

void Builtins::InitializeLocale(const JSHandle<GlobalEnv> &env)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Locale.prototype
    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
    JSHandle<JSObject> localePrototype = factory_->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
    JSHandle<JSTaggedValue> localePrototypeValue(localePrototype);

    // Locale.prototype_or_dynclass
    JSHandle<JSHClass> localeFuncInstanceDynclass =
        factory_->CreateDynClass<JSLocale>(JSType::JS_LOCALE, localePrototypeValue);

    // Locale = new Function()
    JSHandle<JSObject> localeFunction(
        NewIntlConstructor(env, localePrototype, locale::LocaleConstructor, "Locale", FunctionLength::ONE));
    JSHandle<JSFunction>(localeFunction)->SetFunctionPrototype(thread_, JSTaggedValue(*localeFuncInstanceDynclass));
    SetFunctionsGenLocaleProto(env, localePrototype);

    // 10.3.2 Intl.Locale.prototype[ @@toStringTag ]
    SetStringTagSymbol(env, localePrototype, "Intl.Locale");
    env->SetLocaleFunction(thread_, localeFunction);
}

void Builtins::InitializeCollator(const JSHandle<GlobalEnv> &env)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // Collator.prototype
    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
    JSHandle<JSObject> collatorPrototype = factory_->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
    JSHandle<JSTaggedValue> collatorPrototypeValue(collatorPrototype);

    // Collator.prototype_or_dynclass
    JSHandle<JSHClass> collatorFuncInstanceDynclass =
        factory_->CreateDynClass<JSCollator>(JSType::JS_COLLATOR, collatorPrototypeValue);

    // Collator = new Function()
    // 11.1.2 Intl.Collator.prototype.constructor
    JSHandle<JSObject> collatorFunction(
        NewIntlConstructor(env, collatorPrototype, collator::CollatorConstructor, "Collator", FunctionLength::ZERO));
    JSHandle<JSFunction>(collatorFunction)->SetFunctionPrototype(thread_, JSTaggedValue(*collatorFuncInstanceDynclass));

    SetFunctionsGenCollator(env, collatorFunction);

    // Collator.prototype method
    // 11.3.2 Intl.Collator.prototype [ @@toStringTag ]
    SetStringTagSymbol(env, collatorPrototype, "Intl.Collator");
    env->SetCollatorFunction(thread_, collatorFunction);

    SetFunctionsGenCollatorProto(env, collatorPrototype);
}

void Builtins::InitializePluralRules(const JSHandle<GlobalEnv> &env)
{
    [[maybe_unused]] EcmaHandleScope scope(thread_);
    // PluralRules.prototype
    JSHandle<JSTaggedValue> objFun(env->GetObjectFunction());
    JSHandle<JSObject> prPrototype = factory_->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
    JSHandle<JSTaggedValue> prPrototypeValue(prPrototype);

    // PluralRules.prototype_or_dynclass
    JSHandle<JSHClass> prFuncInstanceDynclass =
        factory_->CreateDynClass<JSPluralRules>(JSType::JS_PLURAL_RULES, prPrototypeValue);

    // PluralRules = new Function()
    // 15.2.1 Intl.PluralRules.prototype.constructor
    JSHandle<JSObject> prFunction(NewIntlConstructor(env, prPrototype, plural_rules::PluralRulesConstructor,
                                                     "PluralRules", FunctionLength::ZERO));
    JSHandle<JSFunction>(prFunction)->SetFunctionPrototype(thread_, JSTaggedValue(*prFuncInstanceDynclass));

    env->SetPluralRulesFunction(thread_, prFunction);
    SetFunctionsGenPluralRules(env, prFunction);

    // PluralRules.prototype method
    // 15.4.2 Intl.PluralRules.prototype [ @@toStringTag ]
    SetStringTagSymbol(env, prPrototype, "Intl.PluralRules");

    SetFunctionsGenPluralRulesProto(env, prPrototype);
}

void Builtins::InitializeGcMarker(const JSHandle<GlobalEnv> &env) const
{
    JSHandle<JSObject> marker = factory_->NewEmptyJSObject();
    env->SetGcMarker(thread_, marker.GetTaggedValue());
    SetFunctionsGenGCMarker(env, marker);
}

JSHandle<JSObject> Builtins::InitializeArkTools(const JSHandle<GlobalEnv> &env) const
{
    JSHandle<JSObject> tools = factory_->NewEmptyJSObject();
    SetFunctionsGenArkTools(env, tools);
    return tools;
}

JSHandle<JSObject> Builtins::InitializeArkPrivate(const JSHandle<GlobalEnv> &env) const
{
    JSHandle<JSObject> arkPrivate = factory_->NewEmptyJSObject();
    SetFrozenFunction(env, arkPrivate, "Load", ContainersPrivate::Load, FunctionLength::ZERO);
    SetConstant(arkPrivate, "ArrayList", JSTaggedValue(static_cast<int>(containers::ContainerTag::ARRAY_LIST)));
    SetConstant(arkPrivate, "Queue", JSTaggedValue(static_cast<int>(containers::ContainerTag::QUEUE)));
    SetConstant(arkPrivate, "Deque", JSTaggedValue(static_cast<int>(containers::ContainerTag::DEQUE)));
    SetConstant(arkPrivate, "Stack", JSTaggedValue(static_cast<int>(containers::ContainerTag::STACK)));
    SetConstant(arkPrivate, "Vector", JSTaggedValue(static_cast<int>(containers::ContainerTag::VECTOR)));
    SetConstant(arkPrivate, "List", JSTaggedValue(static_cast<int>(containers::ContainerTag::LIST)));
    SetConstant(arkPrivate, "LinkedList", JSTaggedValue(static_cast<int>(containers::ContainerTag::LINKED_LIST)));
    SetConstant(arkPrivate, "TreeMap", JSTaggedValue(static_cast<int>(containers::ContainerTag::TREE_MAP)));
    SetConstant(arkPrivate, "TreeSet", JSTaggedValue(static_cast<int>(containers::ContainerTag::TREE_SET)));
    SetConstant(arkPrivate, "HashMap", JSTaggedValue(static_cast<int>(containers::ContainerTag::HASH_MAP)));
    SetConstant(arkPrivate, "HashSet", JSTaggedValue(static_cast<int>(containers::ContainerTag::HASH_SET)));
    SetConstant(arkPrivate, "LightWightMap",
                JSTaggedValue(static_cast<int>(containers::ContainerTag::LIGHT_WIGHT_MAP)));
    SetConstant(arkPrivate, "LightWightSet",
                JSTaggedValue(static_cast<int>(containers::ContainerTag::LIGHT_WIGHT_SET)));
    SetConstant(arkPrivate, "PlainArray", JSTaggedValue(static_cast<int>(containers::ContainerTag::PLAIN_ARRAY)));
    return arkPrivate;
}

#ifndef PANDA_PRODUCT_BUILD
JSHandle<JSObject> Builtins::InitializeRuntimeTesting(const JSHandle<GlobalEnv> &env) const
{
    JSHandle<JSObject> runtimeTesting = factory_->NewEmptyJSObject();
    SetFunctionsGenRuntimeTesting(env, runtimeTesting);
    return runtimeTesting;
}
#endif  // PANDA_PRODUCT_BUILD

#ifdef FUZZING_FUZZILLI_BUILTIN
void Builtins::InitializeFuzzilli(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncDynclass)
{
    class BuiltinsFuzzilli {
    public:
        static JSTaggedValue FuzzilliConstructor(EcmaRuntimeCallInfo *argv)
        {
            ASSERT(argv);
            BUILTINS_API_TRACE(argv->GetThread(), Object, ObjectConstructor);
            JSThread *thread = argv->GetThread();
            [[maybe_unused]] EcmaHandleScope handle_scope(thread);

            auto value = builtins_common::GetCallArg(argv, 0);
            JSHandle<EcmaString> command = JSTaggedValue::ToString(thread, value);
            auto commandVal = base::StringHelper::ToStdString(*command);
            if (commandVal == "FUZZILLI_CRASH") {
                JSTaggedNumber num = JSTaggedValue::ToNumber(thread, builtins_common::GetCallArg(argv, 1));
                auto numVal = base::NumberHelper::DoubleInRangeInt32(num.GetNumber());
                switch (numVal) {
                    case 0:
                        *((int *)0x41414141) = 0x1337;
                        break;
                    case 1:
                        ASSERT(false);
                        break;
                    default:
                        ASSERT(false);
                        break;
                }
            } else if (commandVal == "FUZZILLI_PRINT") {
                JSHandle<EcmaString> arg = JSTaggedValue::ToString(thread, builtins_common::GetCallArg(argv, 1));
                auto stringVal = base::StringHelper::ToStdString(*arg);
                // REPRL_DWFD for fuzzilli
                FILE *fzliout = fdopen(103, "w");
                if (!fzliout) {
                    fzliout = stderr;
                    fprintf(fzliout, "Fuzzer output channel not available, printing to stderr instead\n");
                }

                fprintf(fzliout, "%s\n", stringVal.c_str());

                fflush(fzliout);
            }

            return JSTaggedValue::ToObject(thread, value).GetTaggedValue();
        }
    };

    JSHandle<JSObject> fuzzilliFuncPrototype = factory_->NewJSObject(objFuncDynclass);
    JSHandle<JSTaggedValue> fuzzilliFuncPrototypeValue(fuzzilliFuncPrototype);

    JSHandle<JSHClass> fuzzilliFuncInstanceDynclass =
        factory_->CreateDynClass<JSDate>(JSType::JS_FUNCTION, fuzzilliFuncPrototypeValue);

    JSHandle<JSObject> fuzzilliFunction(NewBuiltinConstructor(
        env, fuzzilliFuncPrototype, BuiltinsFuzzilli::FuzzilliConstructor, "fuzzilli", FunctionLength::THREE));
    JSHandle<JSFunction>(fuzzilliFunction)
        ->SetFunctionPrototype(thread_, fuzzilliFuncInstanceDynclass.GetTaggedValue());
}
#endif
}  // namespace ark::ecmascript::builtins
